Hệ thống xếp lịch học tín chỉ cho sinh viên CNTT trên PHP & MySQL
112.147 lượt xem;
1 <?php
2 ########################################################################
3 /*
4 ~~~~~~ LIST OF FUNCTIONS ~~~~~~
5 getTableList() -- returns an associative array of all tables in this application in the format tableName=>tableCaption
6 getThumbnailSpecs($tableName, $fieldName, $view) -- returns an associative array specifying the width, height and identifier of the thumbnail file.
7 createThumbnail($img, $specs) -- $specs is an array as returned by getThumbnailSpecs(). Returns true on success, false on failure.
8 makeSafe($string)
9 checkPermissionVal($pvn)
10 sql($statment, $o)
11 sqlValue($statment)
12 getLoggedAdmin()
13 checkUser($username, $password)
14 logOutUser()
15 getPKFieldName($tn)
16 getCSVData($tn, $pkValue, $stripTag=true)
17 errorMsg($msg)
18 redirect($URL, $absolute=FALSE)
19 htmlRadioGroup($name, $arrValue, $arrCaption, $selectedValue, $selClass="", $class="", $separator="<br>")
20 htmlSelect($name, $arrValue, $arrCaption, $selectedValue, $class="", $selectedClass="")
21 htmlSQLSelect($name, $sql, $selectedValue, $class="", $selectedClass="")
22 isEmail($email) -- returns $email if valid or false otherwise.
23 notifyMemberApproval($memberID) -- send an email to member acknowledging his approval by admin, returns false if no mail is sent
24 setupMembership() -- check if membership tables exist or not. If not, create them.
25 thisOr($this_val, $or) -- return $this_val if it has a value, or $or if not.
26 getUploadedFile($FieldName, $MaxSize=0, $FileTypes='csv|txt', $NoRename=false, $dir='')
27 toBytes($val)
28 convertLegacyOptions($CSVList)
29 getValueGivenCaption($query, $caption)
30 undo_magic_quotes($str)
31 time24($t) -- return time in 24h format
32 time12($t) -- return time in 12h format
33 application_url($page) -- return absolute URL of provided page
34 is_ajax() -- return true if this is an ajax request, false otherwise
35 array_trim($arr) -- recursively trim provided value/array
36 is_allowed_username($username, $exception = false) -- returns username if valid and unique, or false otherwise (if exception is provided and same as username, no uniqueness check is performed)
37 csrf_token($validate) -- csrf-proof a form
38 get_plugins() -- scans for installed plugins and returns them in an array ('name', 'title', 'icon' or 'glyphicon', 'admin_path')
39 maintenance_mode($new_status = '') -- retrieves (and optionally sets) maintenance mode status
40 html_attr($str) -- prepare $str to be placed inside an HTML attribute
41 html_attr_tags_ok($str) -- same as html_attr, but allowing HTML tags
42 Request($var) -- class for providing sanitized values of given request variable (->sql, ->attr, ->html, ->url, and ->raw)
43 Notification() -- class for providing a standardized html notifications functionality
44 sendmail($mail) -- sends an email using PHPMailer as specified in the assoc array $mail( ['to', 'name', 'subject', 'message', 'debug'] ) and returns true on success or an error message on failure
45 safe_html($str) -- sanitize HTML strings, and apply nl2br() to non-HTML ones
46 get_tables_info($skip_authentication = false) -- retrieves table properties as a 2D assoc array ['table_name' => ['prop1' => 'val', ..], ..]
47 getLoggedMemberID() -- returns memberID of logged member. If no login, returns anonymous memberID
48 getLoggedGroupID() -- returns groupID of logged member, or anonymous groupID
49 getMemberInfo() -- returns an array containing the currently signed-in member's info
50 get_group_id($user = '') -- returns groupID of given user, or current one if empty
51 prepare_sql_set($set_array, $glue = ', ') -- Prepares data for a SET or WHERE clause, to be used in an INSERT/UPDATE query
52 insert($tn, $set_array) -- Inserts a record specified by $set_array to the given table $tn
53 update($tn, $set_array, $where_array) -- Updates a record identified by $where_array to date specified by $set_array in the given table $tn
54 set_record_owner($tn, $pk, $user) -- Set/update the owner of given record
55 app_datetime_format($destination = 'php', $datetime = 'd') -- get date/time format string for use with one of these: 'php' (see date function), 'mysql', 'moment'. $datetime: 'd' = date, 't' = time, 'dt' = both
56 mysql_datetime($app_datetime) -- converts $app_datetime to mysql-formatted datetime, 'yyyy-mm-dd H:i:s', or empty string on error
57 app_datetime($mysql_datetime, $datetime = 'd') -- converts $mysql_datetime to app-formatted datetime (if 2nd param is 'dt'), or empty string on error
58 to_utf8($str) -- converts string from app-configured encoding to utf8
59 from_utf8($str) -- converts string from utf8 to app-configured encoding
60 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61 */
62 ########################################################################
63 function get_tables_info($skip_authentication = false){
64 static $all_tables = array(), $accessible_tables = array();
65
66 /* return cached results, if found */
67 if(($skip_authentication || getLoggedAdmin()) && count($all_tables)) return $all_tables;
68 if(!$skip_authentication && count($accessible_tables)) return $accessible_tables;
69
70 /* table groups */
71 $tg = array(
72 'None'
73 );
74
75 $all_tables = array(
76 /* ['table_name' => [table props assoc array] */
77 'schools' => array(
78 'Caption' => 'Schools',
79 'Description' => '',
80 'tableIcon' => 'resources/table_icons/building.png',
81 'group' => $tg[0],
82 'homepageShowCount' => 0
83 ),
84 'departments' => array(
85 'Caption' => 'Departments',
86 'Description' => '',
87 'tableIcon' => 'resources/table_icons/chart_organisation.png',
88 'group' => $tg[0],
89 'homepageShowCount' => 0
90 ),
91 'class_time_table' => array(
92 'Caption' => 'Class time table',
93 'Description' => '',
94 'tableIcon' => 'resources/table_icons/blackboard_drawing.png',
95 'group' => $tg[0],
96 'homepageShowCount' => 0
97 ),
98 'exam_time_table' => array(
99 'Caption' => 'Exam time table',
100 'Description' => '',
101 'tableIcon' => 'resources/table_icons/books.png',
102 'group' => $tg[0],
103 'homepageShowCount' => 0
104 ),
105 'personal_time_table' => array(
106 'Caption' => 'Personal time table',
107 'Description' => '',
108 'tableIcon' => 'resources/table_icons/clock_.png',
109 'group' => $tg[0],
110 'homepageShowCount' => 0
111 ),
112 'student_details' => array(
113 'Caption' => 'Student details',
114 'Description' => '',
115 'tableIcon' => 'resources/table_icons/administrator.png',
116 'group' => $tg[0],
117 'homepageShowCount' => 0
118 ),
119 'notices' => array(
120 'Caption' => 'Notices',
121 'Description' => '',
122 'tableIcon' => 'resources/table_icons/clipboard_empty.png',
123 'group' => $tg[0],
124 'homepageShowCount' => 0
125 )
126 );
127
128 if($skip_authentication || getLoggedAdmin()) return $all_tables;
129
130 foreach($all_tables as $tn => $ti){
131 $arrPerm = getTablePermissions($tn);
132 if($arrPerm[0]) $accessible_tables[$tn] = $ti;
133 }
134
135 return $accessible_tables;
136 }
137 #########################################################
138 if(!function_exists('getTableList')){
139 function getTableList($skip_authentication = false){
140 $arrTables = array(
141 'schools' => 'Schools',
142 'departments' => 'Departments',
143 'class_time_table' => 'Class time table',
144 'exam_time_table' => 'Exam time table',
145 'personal_time_table' => 'Personal time table',
146 'student_details' => 'Student details',
147 'notices' => 'Notices'
148 );
149
150 return $arrTables;
151 }
152 }
153 ########################################################################
154 function getThumbnailSpecs($tableName, $fieldName, $view){
155 return FALSE;
156 }
157 ########################################################################
158 function createThumbnail($img, $specs){
159 $w=$specs['width'];
160 $h=$specs['height'];
161 $id=$specs['identifier'];
162 $path=dirname($img);
163
164 // image doesn't exist or inaccessible?
165 if(!$size=@getimagesize($img)) return FALSE;
166
167 // calculate thumbnail size to maintain aspect ratio
168 $ow=$size[0]; // original image width
169 $oh=$size[1]; // original image height
170 $twbh=$h/$oh*$ow; // calculated thumbnail width based on given height
171 $thbw=$w/$ow*$oh; // calculated thumbnail height based on given width
172 if($w && $h){
173 if($twbh>$w) $h=$thbw;
174 if($thbw>$h) $w=$twbh;
175 }elseif($w){
176 $h=$thbw;
177 }elseif($h){
178 $w=$twbh;
179 }else{
180 return FALSE;
181 }
182
183 // dir not writeable?
184 if(!is_writable($path)) return FALSE;
185
186 // GD lib not loaded?
187 if(!function_exists('gd_info')) return FALSE;
188 $gd=gd_info();
189
190 // GD lib older than 2.0?
191 preg_match('/\d/', $gd['GD Version'], $gdm);
192 if($gdm[0]<2) return FALSE;
193
194 // get file extension
195 preg_match('/\.[a-zA-Z]{3,4}$/U', $img, $matches);
196 $ext=strtolower($matches[0]);
197
198 // check if supplied image is supported and specify actions based on file type
199 if($ext=='.gif'){
200 if(!$gd['GIF Create Support']) return FALSE;
201 $thumbFunc='imagegif';
202 }elseif($ext=='.png'){
203 if(!$gd['PNG Support']) return FALSE;
204 $thumbFunc='imagepng';
205 }elseif($ext=='.jpg' || $ext=='.jpe' || $ext=='.jpeg'){
206 if(!$gd['JPG Support'] && !$gd['JPEG Support']) return FALSE;
207 $thumbFunc='imagejpeg';
208 }else{
209 return FALSE;
210 }
211
212 // determine thumbnail file name
213 $ext=$matches[0];
214 $thumb=substr($img, 0, -5).str_replace($ext, $id.$ext, substr($img, -5));
215
216 // if the original image smaller than thumb, then just copy it to thumb
217 if($h>$oh && $w>$ow){
218 return (@copy($img, $thumb) ? TRUE : FALSE);
219 }
220
221 // get image data
222 if(!$imgData=imagecreatefromstring(implode('', file($img)))) return FALSE;
223
224 // finally, create thumbnail
225 $thumbData=imagecreatetruecolor($w, $h);
226
227 //preserve transparency of png and gif images
228 if($thumbFunc=='imagepng'){
229 if(($clr=@imagecolorallocate($thumbData, 0, 0, 0))!=-1){
230 @imagecolortransparent($thumbData, $clr);
231 @imagealphablending($thumbData, false);
232 @imagesavealpha($thumbData, true);
233 }
234 }elseif($thumbFunc=='imagegif'){
235 @imagealphablending($thumbData, false);
236 $transIndex=imagecolortransparent($imgData);
237 if($transIndex>=0){
238 $transClr=imagecolorsforindex($imgData, $transIndex);
239 $transIndex=imagecolorallocatealpha($thumbData, $transClr['red'], $transClr['green'], $transClr['blue'], 127);
240 imagefill($thumbData, 0, 0, $transIndex);
241 }
242 }
243
244 // resize original image into thumbnail
245 if(!imagecopyresampled($thumbData, $imgData, 0, 0 , 0, 0, $w, $h, $ow, $oh)) return FALSE;
246 unset($imgData);
247
248 // gif transparency
249 if($thumbFunc=='imagegif' && $transIndex>=0){
250 imagecolortransparent($thumbData, $transIndex);
251 for($y=0; $y<$h; ++$y)
252 for($x=0; $x<$w; ++$x)
253 if(((imagecolorat($thumbData, $x, $y)>>24) & 0x7F) >= 100) imagesetpixel($thumbData, $x, $y, $transIndex);
254 imagetruecolortopalette($thumbData, true, 255);
255 imagesavealpha($thumbData, false);
256 }
257
258 if(!$thumbFunc($thumbData, $thumb)) return FALSE;
259 unset($thumbData);
260
261 return TRUE;
262 }
263 ########################################################################
264 function makeSafe($string, $is_gpc = true){
265 if($is_gpc) $string = (get_magic_quotes_gpc() ? stripslashes($string) : $string);
266 if(!db_link()){ sql("select 1+1", $eo); }
267
268 // prevent double escaping
269 $na = explode(',', "\x00,\n,\r,',\",\x1a");
270 $escaped = true;
271 $nosc = true; // no special chars exist
272 foreach($na as $ns){
273 $dan = substr_count($string, $ns);
274 $esdan = substr_count($string, "\\{$ns}");
275 if($dan != $esdan) $escaped = false;
276 if($dan) $nosc = false;
277 }
278 if($nosc){
279 // find unescaped \
280 $dan = substr_count($string, '\\');
281 $esdan = substr_count($string, '\\\\');
282 if($dan != $esdan * 2) $escaped = false;
283 }
284
285 return ($escaped ? $string : db_escape($string));
286 }
287 ########################################################################
288 function checkPermissionVal($pvn){
289 // fn to make sure the value in the given POST variable is 0, 1, 2 or 3
290 // if the value is invalid, it default to 0
291 $pvn=intval($_POST[$pvn]);
292 if($pvn!=1 && $pvn!=2 && $pvn!=3){
293 return 0;
294 }else{
295 return $pvn;
296 }
297 }
298 ########################################################################
299 if(!function_exists('sql')){
300 function sql($statment, &$o){
301
302 /*
303 Supported options that can be passed in $o options array (as array keys):
304 'silentErrors': If true, errors will be returned in $o['error'] rather than displaying them on screen and exiting.
305 */
306
307 global $Translation;
308 static $connected = false, $db_link;
309
310 $dbServer = config('dbServer');
311 $dbUsername = config('dbUsername');
312 $dbPassword = config('dbPassword');
313 $dbDatabase = config('dbDatabase');
314
315 ob_start();
316
317 if(!$connected){
318 /****** Connect to MySQL ******/
319 if(!extension_loaded('mysql') && !extension_loaded('mysqli')){
320 $o['error'] = 'PHP is not configured to connect to MySQL on this machine. Please see <a href="http://www.php.net/manual/en/ref.mysql.php">this page</a> for help on how to configure MySQL.';
321 if($o['silentErrors']) return false;
322
323 echo Notification::placeholder();
324 echo Notification::show(array(
325 'message' => $o['error'],
326 'class' => 'danger',
327 'dismiss_seconds' => 7200
328 ));
329 echo ob_get_clean();
330 exit;
331 }
332
333 if(!($db_link = @db_connect($dbServer, $dbUsername, $dbPassword))){
334 $o['error'] = db_error($db_link, true);
335 if($o['silentErrors']) return false;
336
337 echo Notification::placeholder();
338 echo Notification::show(array(
339 'message' => $o['error'],
340 'class' => 'danger',
341 'dismiss_seconds' => 7200
342 ));
343 echo ob_get_clean();
344 exit;
345 }
346
347 /****** Select DB ********/
348 if(!db_select_db($dbDatabase, $db_link)){
349 $o['error'] = db_error($db_link);
350 if($o['silentErrors']) return false;
351
352 echo Notification::placeholder();
353 echo Notification::show(array(
354 'message' => $o['error'],
355 'class' => 'danger',
356 'dismiss_seconds' => 7200
357 ));
358 echo ob_get_clean();
359 exit;
360 }
361
362 $connected = true;
363 }
364
365 if(!$result = @db_query($statment, $db_link)){
366 if(!stristr($statment, "show columns")){
367 // retrieve error codes
368 $errorNum = db_errno($db_link);
369 $errorMsg = htmlspecialchars(db_error($db_link));
370
371 if(getLoggedAdmin()) $errorMsg .= "<pre class=\"ltr\">{$Translation['query:']}\n" . htmlspecialchars($statment) . "</pre><i class=\"text-right\">{$Translation['admin-only info']}</i>";
372
373 if($o['silentErrors']){ $o['error'] = $errorMsg; return false; }
374
375 echo Notification::placeholder();
376 echo Notification::show(array(
377 'message' => $errorMsg,
378 'class' => 'danger',
379 'dismiss_seconds' => 7200
380 ));
381 echo ob_get_clean();
382 exit;
383 }
384 }
385
386 ob_end_clean();
387 return $result;
388 }
389 }
390
391 ########################################################################
392 function sqlValue($statment){
393 // executes a statment that retreives a single data value and returns the value retrieved
394 if(!$res=sql($statment, $eo)){
395 return FALSE;
396 }
397 if(!$row=db_fetch_row($res)){
398 return FALSE;
399 }
400 return $row[0];
401 }
402 ########################################################################
403 function getLoggedAdmin(){
404 // checks session variables to see whether the admin is logged or not
405 // if not, it returns FALSE
406 // if logged, it returns the user id
407
408 $adminConfig = config('adminConfig');
409
410 if($_SESSION['adminUsername']!=''){
411 return $_SESSION['adminUsername'];
412 }elseif($_SESSION['memberID']==$adminConfig['adminUsername']){
413 $_SESSION['adminUsername']=$_SESSION['memberID'];
414 return $_SESSION['adminUsername'];
415 }else{
416 return FALSE;
417 }
418 }
419 ########################################################################
420 function checkUser($username, $password){
421 // checks given username and password for validity
422 // if valid, registers the username in a session and returns true
423 // else, return FALSE and destroys session
424
425 $adminConfig = config('adminConfig');
426 if($username != $adminConfig['adminUsername'] || md5($password) != $adminConfig['adminPassword']){
427 return FALSE;
428 }
429
430 $_SESSION['adminUsername'] = $username;
431 $_SESSION['memberGroupID'] = sqlValue("select groupID from membership_users where memberID='" . makeSafe($username) ."'");
432 $_SESSION['memberID'] = $username;
433 return TRUE;
434 }
435 ########################################################################
436 function logOutUser(){
437 // destroys current session
438 if(isset($_COOKIE[session_name()])){
439 setcookie(session_name(), '', time() - 42000, '/');
440 }
441 if(isset($_COOKIE[session_name() . '_rememberMe'])){
442 setcookie(session_name() . '_rememberMe', '', time() - 42000);
443 }
444 session_destroy();
445 $_SESSION = array();
446 }
447 ########################################################################
448 function getPKFieldName($tn){
449 // get pk field name of given table
450
451 $stn = makeSafe($tn, false);
452 if(!$res = sql("show fields from `$stn`", $eo)){
453 return false;
454 }
455
456 while($row = db_fetch_assoc($res)){
457 if($row['Key'] == 'PRI'){
458 return $row['Field'];
459 }
460 }
461
462 return false;
463 }
464 ########################################################################
465 function getCSVData($tn, $pkValue, $stripTags=true){
466 // get pk field name for given table
467 if(!$pkField=getPKFieldName($tn)){
468 return "";
469 }
470
471 // get a concat string to produce a csv list of field values for given table record
472 if(!$res=sql("show fields from `$tn`", $eo)){
473 return "";
474 }
475 while($row=db_fetch_assoc($res)){
476 $csvFieldList.="`{$row['Field']}`,";
477 }
478 $csvFieldList=substr($csvFieldList, 0, -1);
479
480 $csvData=sqlValue("select CONCAT_WS(', ', $csvFieldList) from `$tn` where `$pkField`='" . makeSafe($pkValue, false) . "'");
481
482 return ($stripTags ? strip_tags($csvData) : $csvData);
483 }
484 ########################################################################
485 function errorMsg($msg){
486 echo "<div class=\"alert alert-danger\">{$msg}</div>";
487 }
488 ########################################################################
489 function redirect($url, $absolute = false){
490 $fullURL = ($absolute ? $url : application_url($url));
491 if(!headers_sent()) header("Location: {$fullURL}");
492
493 echo "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;url={$fullURL}\">";
494 echo "<br><br><a href=\"{$fullURL}\">Click here</a> if you aren't automatically redirected.";
495 exit;
496 }
497 ########################################################################
498 function htmlRadioGroup($name, $arrValue, $arrCaption, $selectedValue, $selClass = "text-primary", $class = "", $separator = "<br>"){
499 if(!is_array($arrValue)) return '';
500
501 ob_start();
502 ?>
503 <div class="radio %%CLASS%%"><label>
504 <input type="radio" name="%%NAME%%" id="%%ID%%" value="%%VALUE%%" %%CHECKED%%> %%LABEL%%
505 </label></div>
506 <?php
507 $template = ob_get_contents();
508 ob_end_clean();
509
510 $out = '';
511 for($i = 0; $i < count($arrValue); $i++){
512 $replacements = array(
513 '%%CLASS%%' => html_attr($arrValue[$i] == $selectedValue ? $selClass :$class),
514 '%%NAME%%' => html_attr($name),
515 '%%ID%%' => html_attr($name . $i),
516 '%%VALUE%%' => html_attr($arrValue[$i]),
517 '%%LABEL%%' => $arrCaption[$i],
518 '%%CHECKED%%' => ($arrValue[$i]==$selectedValue ? " checked" : "")
519 );
520 $out .= str_replace(array_keys($replacements), array_values($replacements), $template);
521 }
522
523 return $out;
524 }
525 ########################################################################
526 function htmlSelect($name, $arrValue, $arrCaption, $selectedValue, $class="", $selectedClass=""){
527 if($selectedClass==""){
528 $selectedClass=$class;
529 }
530 if(is_array($arrValue)){
531 $out="<select name=\"$name\" id=\"$name\">";
532 for($i=0; $i<count($arrValue); $i++){
533 $out.="<option value=\"".$arrValue[$i]."\"".($arrValue[$i]==$selectedValue ? " selected class=\"$class\"" : " class=\"$selectedClass\"").">".$arrCaption[$i]."</option>";
534 }
535 $out.="</select>";
536 }
537 return $out;
538 }
539 ########################################################################
540 function htmlSQLSelect($name, $sql, $selectedValue, $class="", $selectedClass=""){
541 $arrVal[]='';
542 $arrCap[]='';
543 if($res=sql($sql, $eo)){
544 while($row=db_fetch_row($res)){
545 $arrVal[]=$row[0];
546 $arrCap[]=$row[1];
547 }
548 return htmlSelect($name, $arrVal, $arrCap, $selectedValue, $class, $selectedClass);
549 }else{
550 return "";
551 }
552 }
553 ########################################################################
554 function bootstrapSelect($name, $arrValue, $arrCaption, $selectedValue, $class = '', $selectedClass = ''){
555 if($selectedClass == '') $selectedClass = $class;
556
557 $out = "<select class=\"form-control\" name=\"{$name}\" id=\"{$name}\">";
558 if(is_array($arrValue)){
559 for($i = 0; $i < count($arrValue); $i++){
560 $selected = "class=\"{$class}\"";
561 if($arrValue[$i] == $selectedValue) $selected = "selected class=\"{$selectedClass}\"";
562 $out .= "<option value=\"{$arrValue[$i]}\" {$selected}>{$arrCaption[$i]}</option>";
563 }
564 }
565 $out .= '</select>';
566
567 return $out;
568 }
569 ########################################################################
570 function bootstrapSQLSelect($name, $sql, $selectedValue, $class = '', $selectedClass = ''){
571 $arrVal[] = '';
572 $arrCap[] = '';
573 if($res = sql($sql, $eo)){
574 while($row = db_fetch_row($res)){
575 $arrVal[] = $row[0];
576 $arrCap[] = $row[1];
577 }
578 return bootstrapSelect($name, $arrVal, $arrCap, $selectedValue, $class, $selectedClass);
579 }
580
581 return '';
582 }
583 ########################################################################
584 function isEmail($email){
585 if(preg_match('/^([*+!.&#$¦\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,45})$/i', $email)){
586 return $email;
587 }else{
588 return FALSE;
589 }
590 }
591 ########################################################################
592 function notifyMemberApproval($memberID){
593 $adminConfig = config('adminConfig');
594 $memberID = strtolower($memberID);
595
596 $email = sqlValue("select email from membership_users where lcase(memberID)='{$memberID}'");
597
598 return sendmail(array(
599 'to' => $email,
600 'name' => $memberID,
601 'subject' => $adminConfig['approvalSubject'],
602 'message' => nl2br($adminConfig['approvalMessage'])
603 ));
604 }
605 ########################################################################
606 function setupMembership(){
607 // run once per request
608 static $executed = false;
609 if($executed) return;
610 $executed = true;
611
612 /* abort if current page is one of the following exceptions */
613 $exceptions = array('pageEditMember.php', 'membership_passwordReset.php', 'membership_profile.php', 'membership_signup.php', 'pageChangeMemberStatus.php', 'pageDeleteGroup.php', 'pageDeleteMember.php', 'pageEditGroup.php', 'pageEditMemberPermissions.php', 'pageRebuildFields.php', 'pageSettings.php');
614 if(in_array(basename($_SERVER['PHP_SELF']), $exceptions)) return;
615
616 $eo = array('silentErrors' => true);
617
618 $adminConfig = config('adminConfig');
619 $today = @date('Y-m-d');
620
621 $membership_tables = array(
622 'membership_groups' => "CREATE TABLE IF NOT EXISTS membership_groups (groupID int unsigned NOT NULL auto_increment, name varchar(20), description text, allowSignup tinyint, needsApproval tinyint, PRIMARY KEY (groupID)) CHARSET " . mysql_charset,
623 'membership_users' => "CREATE TABLE IF NOT EXISTS membership_users (memberID varchar(20) NOT NULL, passMD5 varchar(40), email varchar(100), signupDate date, groupID int unsigned, isBanned tinyint, isApproved tinyint, custom1 text, custom2 text, custom3 text, custom4 text, comments text, PRIMARY KEY (memberID)) CHARSET " . mysql_charset,
624 'membership_grouppermissions' => "CREATE TABLE IF NOT EXISTS membership_grouppermissions (permissionID int unsigned NOT NULL auto_increment, groupID int, tableName varchar(100), allowInsert tinyint, allowView tinyint NOT NULL DEFAULT '0', allowEdit tinyint NOT NULL DEFAULT '0', allowDelete tinyint NOT NULL DEFAULT '0', PRIMARY KEY (permissionID)) CHARSET " . mysql_charset,
625 'membership_userrecords' => "CREATE TABLE IF NOT EXISTS membership_userrecords (recID bigint unsigned NOT NULL auto_increment, tableName varchar(100), pkValue varchar(255), memberID varchar(20), dateAdded bigint unsigned, dateUpdated bigint unsigned, groupID int, PRIMARY KEY (recID)) CHARSET " . mysql_charset,
626 'membership_userpermissions' => "CREATE TABLE IF NOT EXISTS membership_userpermissions (permissionID int unsigned NOT NULL auto_increment, memberID varchar(20) NOT NULL, tableName varchar(100), allowInsert tinyint, allowView tinyint NOT NULL DEFAULT '0', allowEdit tinyint NOT NULL DEFAULT '0', allowDelete tinyint NOT NULL DEFAULT '0', PRIMARY KEY (permissionID)) CHARSET " . mysql_charset
627 );
628
629 // get db tables
630 $tables = array();
631 $res = sql("show tables", $eo);
632
633 if(!$res){
634 include_once(dirname(__FILE__) . '/../header.php');
635 echo $eo['error'];
636 include_once(dirname(__FILE__) . '/../footer.php');
637 exit;
638 }
639
640 while($row = db_fetch_array($res)) $tables[] = $row[0];
641
642 // check if membership tables exist or not
643 foreach($membership_tables as $tn => $tdef){
644 if(!in_array($tn, $tables)){
645 sql($tdef, $eo);
646 }
647 }
648
649 // check membership_users definition
650 $membership_users = array();
651 $res = sql("show columns from membership_users", $eo);
652 while($row = db_fetch_assoc($res)) $membership_users[$row['Field']] = $row;
653
654 if(!in_array('pass_reset_key', array_keys($membership_users))) @db_query("ALTER TABLE membership_users ADD COLUMN pass_reset_key VARCHAR(100)");
655 if(!in_array('pass_reset_expiry', array_keys($membership_users))) @db_query("ALTER TABLE membership_users ADD COLUMN pass_reset_expiry INT UNSIGNED");
656 if(!$membership_users['groupID']['Key']) @db_query("ALTER TABLE membership_users ADD INDEX groupID (groupID)");
657
658 // create membership indices if not existing
659 $membership_userrecords = array();
660 $res = sql("show keys from membership_userrecords", $eo);
661 while($row = db_fetch_assoc($res)) $membership_userrecords[$row['Key_name']][$row['Seq_in_index']] = $row;
662
663 if(!$membership_userrecords['pkValue'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX pkValue (pkValue)");
664 if(!$membership_userrecords['tableName'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX tableName (tableName)");
665 if(!$membership_userrecords['memberID'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX memberID (memberID)");
666 if(!$membership_userrecords['groupID'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX groupID (groupID)");
667 if(!$membership_userrecords['tableName_pkValue'][1] || !$membership_userrecords['tableName_pkValue'][2]) @db_query("ALTER IGNORE TABLE membership_userrecords ADD UNIQUE INDEX tableName_pkValue (tableName, pkValue)");
668
669 // retreive anonymous and admin groups and their permissions
670 $anon_group = $adminConfig['anonymousGroup'];
671 $anon_user = strtolower($adminConfig['anonymousMember']);
672 $admin_group = 'Admins';
673 $admin_user = strtolower($adminConfig['adminUsername']);
674 $groups_permissions = array();
675 $res = sql(
676 "select g.groupID, g.name, gp.tableName, gp.allowInsert, gp.allowView, gp.allowEdit, gp.allowDelete " .
677 "from membership_groups g left join membership_grouppermissions gp on g.groupID=gp.groupID " .
678 "where g.name='" . makeSafe($admin_group) . "' or g.name='" . makeSafe($anon_group) . "' " .
679 "order by g.groupID, gp.tableName", $eo
680 );
681 while($row = db_fetch_assoc($res)) $groups_permissions[] = $row;
682
683 // check anonymous group and user and create if necessary
684 $anon_group_id = false;
685 foreach($groups_permissions as $group){
686 if($group['name'] == $anon_group){
687 $anon_group_id = $group['groupID'];
688 break;
689 }
690 }
691
692 if(!$anon_group_id){
693 sql("insert into membership_groups set name='" . makeSafe($anon_group) . "', allowSignup=0, needsApproval=0, description='Anonymous group created automatically on " . @date("Y-m-d") . "'", $eo);
694 $anon_group_id = db_insert_id();
695 }
696
697 if($anon_group_id){
698 $anon_user_db = sqlValue("select lcase(memberID) from membership_users where lcase(memberID)='" . makeSafe($anon_user) . "' and groupID='{$anon_group_id}'");
699 if(!$anon_user_db || $anon_user_db != $anon_user){
700 sql("delete from membership_users where groupID='{$anon_group_id}'", $eo);
701 sql("insert into membership_users set memberID='" . makeSafe($anon_user) . "', signUpDate='{$today}', groupID='{$anon_group_id}', isBanned=0, isApproved=1, comments='Anonymous member created automatically on {$today}'", $eo);
702 }
703 }
704
705 // check admin group and user and create if necessary
706 $admin_group_id = false;
707 foreach($groups_permissions as $group){
708 if($group['name'] == $admin_group){
709 $admin_group_id = $group['groupID'];
710 break;
711 }
712 }
713
714 if(!$admin_group_id){
715 sql("insert into membership_groups set name='" . makeSafe($admin_group) . "', allowSignup=0, needsApproval=1, description='Admin group created automatically on {$today}'", $eo);
716 $admin_group_id = db_insert_id();
717 }
718
719 if($admin_group_id){
720 // check that admins can access all tables
721 $all_tables = getTableList(true);
722 $tables_ok = $perms_ok = array();
723 foreach($all_tables as $tn => $tc) $tables_ok[$tn] = $perms_ok[$tn] = false;
724
725 foreach($groups_permissions as $group){
726 if($group['name'] == $admin_group){
727 if(isset($tables_ok[$group['tableName']])){
728 $tables_ok[$group['tableName']] = true;
729 if($group['allowInsert'] == 1 && $group['allowDelete'] == 3 && $group['allowEdit'] == 3 && $group['allowView'] == 3){
730 $perms_ok[$group['tableName']] = true;
731 }
732 }
733 }
734 }
735
736 // if any table has no record in Admins permissions, create one for it
737 $grant_sql = array();
738 foreach($tables_ok as $tn => $status){
739 if(!$status) $grant_sql[] = "({$admin_group_id}, '{$tn}')";
740 }
741
742 if(count($grant_sql)){
743 sql("insert into membership_grouppermissions (groupID, tableName) values " . implode(',', $grant_sql), $eo);
744 }
745
746 // check admin permissions and update if necessary
747 $perms_sql = array();
748 foreach($perms_ok as $tn => $status){
749 if(!$status) $perms_sql[] = "'{$tn}'";
750 }
751
752 if(count($perms_sql)){
753 sql("update membership_grouppermissions set allowInsert=1, allowView=3, allowEdit=3, allowDelete=3 where groupID={$admin_group_id} and tableName in (" . implode(',', $perms_sql) . ")", $eo);
754 }
755
756 // check if super admin is stored in the users table and add him if not
757 $admin_user_exists = sqlValue("select count(1) from membership_users where lcase(memberID)='" . makeSafe($admin_user)."' and groupID='{$admin_group_id}'");
758 if(!$admin_user_exists){
759 sql("insert into membership_users set memberID='" . makeSafe($admin_user) . "', passMD5='{$adminConfig['adminPassword']}', email='{$adminConfig['senderEmail']}', signUpDate='{$today}', groupID='{$admin_group_id}', isBanned=0, isApproved=1, comments='Admin member created automatically on {$today}'", $eo);
760 }
761 }
762 }
763
764 ########################################################################
765 function thisOr($this_val, $or = ' '){
766 return ($this_val != '' ? $this_val : $or);
767 }
768 ########################################################################
769 function getUploadedFile($FieldName, $MaxSize=0, $FileTypes='csv|txt', $NoRename=false, $dir=''){
770 $currDir=dirname(__FILE__);
771 if(is_array($_FILES)){
772 $f = $_FILES[$FieldName];
773 }else{
774 return 'Your php settings don\'t allow file uploads.';
775 }
776
777 if(!$MaxSize){
778 $MaxSize=toBytes(ini_get('upload_max_filesize'));
779 }
780
781 if(!is_dir("$currDir/csv")){
782 @mkdir("$currDir/csv");
783 }
784
785 $dir=(is_dir($dir) && is_writable($dir) ? $dir : "$currDir/csv/");
786
787 if($f['error']!=4 && $f['name']!=''){
788 if($f['size']>$MaxSize || $f['error']){
789 return 'File size exceeds maximum allowed of '.intval($MaxSize / 1024).'KB';
790 }
791 if(!preg_match('/\.('.$FileTypes.')$/i', $f['name'], $ft)){
792 return 'File type not allowed. Only these file types are allowed: '.str_replace('|', ', ', $FileTypes);
793 }
794
795 if($NoRename){
796 $n = str_replace(' ', '_', $f['name']);
797 }else{
798 $n = microtime();
799 $n = str_replace(' ', '_', $n);
800 $n = str_replace('0.', '', $n);
801 $n .= $ft[0];
802 }
803
804 if(!@move_uploaded_file($f['tmp_name'], $dir . $n)){
805 return 'Couldn\'t save the uploaded file. Try chmoding the upload folder "'.$dir.'" to 777.';
806 }else{
807 @chmod($dir.$n, 0666);
808 return $dir.$n;
809 }
810 }
811 return 'An error occured while uploading the file. Please try again.';
812 }
813 ########################################################################
814 function toBytes($val){
815 $val = trim($val);
816 $last = strtolower($val{strlen($val)-1});
817 switch($last){
818 // The 'G' modifier is available since PHP 5.1.0
819 case 'g':
820 $val *= 1024;
821 case 'm':
822 $val *= 1024;
823 case 'k':
824 $val *= 1024;
825 }
826
827 return $val;
828 }
829 ########################################################################
830 function convertLegacyOptions($CSVList){
831 $CSVList=str_replace(';;;', ';||', $CSVList);
832 $CSVList=str_replace(';;', '||', $CSVList);
833 return $CSVList;
834 }
835 ########################################################################
836 function getValueGivenCaption($query, $caption){
837 if(!preg_match('/select\s+(.*?)\s*,\s*(.*?)\s+from\s+(.*?)\s+order by.*/i', $query, $m)){
838 if(!preg_match('/select\s+(.*?)\s*,\s*(.*?)\s+from\s+(.*)/i', $query, $m)){
839 return '';
840 }
841 }
842
843 // get where clause if present
844 if(preg_match('/\s+from\s+(.*?)\s+where\s+(.*?)\s+order by.*/i', $query, $mw)){
845 $where="where ($mw[2]) AND";
846 $m[3]=$mw[1];
847 }else{
848 $where='where';
849 }
850
851 $caption=makeSafe($caption);
852 return sqlValue("SELECT $m[1] FROM $m[3] $where $m[2]='$caption'");
853 }
854 ########################################################################
855 function undo_magic_quotes($str){
856 return (get_magic_quotes_gpc() ? stripslashes($str) : $str);
857 }
858 ########################################################################
859 function time24($t = false){
860 if($t === false) $t = date('Y-m-d H:i:s'); // time now if $t not passed
861 elseif(!$t) return ''; // empty string if $t empty
862 return date('H:i:s', strtotime($t));
863 }
864 ########################################################################
865 function time12($t = false){
866 if($t === false) $t = date('Y-m-d H:i:s'); // time now if $t not passed
867 elseif(!$t) return ''; // empty string if $t empty
868 return date('h:i:s A', strtotime($t));
869 }
870 ########################################################################
871 function application_url($page = '', $s = false){
872 if($s === false) $s = $_SERVER;
873 $ssl = (!empty($s['HTTPS']) && $s['HTTPS'] == 'on');
874 $http = ($ssl ? 'https:' : 'http:');
875 $port = $s['SERVER_PORT'];
876 $port = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port;
877 $host = (isset($s['HTTP_HOST']) ? $s['HTTP_HOST'] : $s['SERVER_NAME'] . $port);
878 $uri = dirname($s['SCRIPT_NAME']);
879
880 /* app folder name (without the ending /admin part) */
881 $app_folder_is_admin = false;
882 $app_folder = substr(dirname(__FILE__), 0, -6);
883 if(substr($app_folder, -6, 6) == '/admin' || substr($app_folder, -6, 6) == '\\admin')
884 $app_folder_is_admin = true;
885
886 if(substr($uri, -12, 12) == '/admin/admin') $uri = substr($uri, 0, -6);
887 elseif(substr($uri, -6, 6) == '/admin' && !$app_folder_is_admin) $uri = substr($uri, 0, -6);
888 elseif($uri == '/' || $uri == '\\') $uri = '';
889
890 return "{$http}//{$host}{$uri}/{$page}";
891 }
892 ########################################################################
893 function is_ajax(){
894 return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
895 }
896 ########################################################################
897 function array_trim($arr){
898 if(!is_array($arr)) return trim($arr);
899 return array_map('array_trim', $arr);
900 }
901 ########################################################################
902 function is_allowed_username($username, $exception = false){
903 $username = trim(strtolower($username));
904 if(!preg_match('/^[a-z0-9][a-z0-9 _.@]{3,19}$/', $username) || preg_match('/(@@| |\.\.|___)/', $username)) return false;
905
906 if($username == $exception) return $username;
907
908 if(sqlValue("select count(1) from membership_users where lcase(memberID)='{$username}'")) return false;
909 return $username;
910 }
911 ########################################################################
912 /*
913 if called without parameters, looks for a non-expired token in the user's session (or creates one if
914 none found) and returns html code to insert into the form to be protected.
915
916 if set to true, validates token sent in $_REQUEST against that stored in the session
917 and returns true if valid or false if invalid, absent or expired.
918
919 usage:
920 1. in a new form that needs csrf proofing: echo csrf_token();
921 >> in case of ajax requests and similar, retrieve token directly
922 by calling csrf_token(false, true);
923 2. when validating a submitted form: if(!csrf_token(true)){ reject_submission_somehow(); }
924 */
925 function csrf_token($validate = false, $token_only = false){
926 $token_age = 60 * 60;
927 /* retrieve token from session */
928 $csrf_token = (isset($_SESSION['csrf_token']) ? $_SESSION['csrf_token'] : false);
929 $csrf_token_expiry = (isset($_SESSION['csrf_token_expiry']) ? $_SESSION['csrf_token_expiry'] : false);
930
931 if(!$validate){
932 /* create a new token if necessary */
933 if($csrf_token_expiry < time() || !$csrf_token){
934 $csrf_token = md5(uniqid(rand(), true));
935 $csrf_token_expiry = time() + $token_age;
936 $_SESSION['csrf_token'] = $csrf_token;
937 $_SESSION['csrf_token_expiry'] = $csrf_token_expiry;
938 }
939
940 if($token_only) return $csrf_token;
941 return '<input type="hidden" id="csrf_token" name="csrf_token" value="' . $csrf_token . '">';
942 }
943
944 /* validate submitted token */
945 $user_token = (isset($_REQUEST['csrf_token']) ? $_REQUEST['csrf_token'] : false);
946 if($csrf_token_expiry < time() || !$user_token || $user_token != $csrf_token){
947 return false;
948 }
949
950 return true;
951 }
952 ########################################################################
953 function get_plugins(){
954 $plugins = array();
955 $plugins_path = dirname(__FILE__) . '/../plugins/';
956
957 if(!is_dir($plugins_path)) return $plugins;
958
959 $pd = dir($plugins_path);
960 while(false !== ($plugin = $pd->read())){
961 if(!is_dir($plugins_path . $plugin) || in_array($plugin, array('projects', 'plugins-resources', '.', '..'))) continue;
962
963 $info_file = "{$plugins_path}{$plugin}/plugin-info.json";
964 if(!is_file($info_file)) continue;
965
966 $plugins[] = json_decode(file_get_contents($info_file), true);
967 $plugins[count($plugins) - 1]['admin_path'] = "../plugins/{$plugin}";
968 }
969 $pd->close();
970
971 return $plugins;
972 }
973 ########################################################################
974 function maintenance_mode($new_status = ''){
975 $maintenance_file = dirname(__FILE__) . '/.maintenance';
976
977 if($new_status === true){
978 /* turn on maintenance mode */
979 @touch($maintenance_file);
980 }elseif($new_status === false){
981 /* turn off maintenance mode */
982 @unlink($maintenance_file);
983 }
984
985 /* return current maintenance mode status */
986 return is_file($maintenance_file);
987 }
988 ########################################################################
989 function handle_maintenance($echo = false){
990 if(!maintenance_mode()) return;
991
992 global $Translation;
993 $adminConfig = config('adminConfig');
994
995 $admin = getLoggedAdmin();
996 if($admin){
997 return ($echo ? '<div class="alert alert-danger" style="margin: 5em auto -5em;"><b>' . $Translation['maintenance mode admin notification'] . '</b></div>' : '');
998 }
999
1000 if(!$echo) exit;
1001
1002 exit('<div class="alert alert-danger" style="margin-top: 5em; font-size: 2em;"><i class="glyphicon glyphicon-exclamation-sign"></i> ' . $adminConfig['maintenance_mode_message'] . '</div>');
1003 }
1004 #########################################################
1005 function html_attr($str){
1006 if(version_compare(PHP_VERSION, '5.2.3') >= 0) return htmlspecialchars($str, ENT_QUOTES, datalist_db_encoding, false);
1007 return htmlspecialchars($str, ENT_QUOTES, datalist_db_encoding);
1008 }
1009 #########################################################
1010 function html_attr_tags_ok($str){
1011 // use this instead of html_attr() if you don't want html tags to be escaped
1012 $new_str = html_attr($str);
1013 return str_replace(array('<', '>'), array('<', '>'), $new_str);
1014 }
1015 #########################################################
1016 class Request{
1017 var $sql, $url, $attr, $html, $raw;
1018
1019 function __construct($var, $filter = false){
1020 $this->Request($var, $filter);
1021 }
1022
1023 function Request($var, $filter = false){
1024 $unsafe = (isset($_REQUEST[$var]) ? $_REQUEST[$var] : '');
1025 if(get_magic_quotes_gpc()) $unsafe = stripslashes($unsafe);
1026
1027 if($filter){
1028 $unsafe = call_user_func($filter, $unsafe);
1029 }
1030
1031 $this->sql = makeSafe($unsafe, false);
1032 $this->url = urlencode($unsafe);
1033 $this->attr = html_attr($unsafe);
1034 $this->html = html_attr($unsafe);
1035 $this->raw = $unsafe;
1036 }
1037 }
1038 #########################################################
1039 class Notification{
1040 /*
1041 Usage:
1042 * in the main document, initiate notifications support using this PHP code:
1043 echo Notification::placeholder();
1044
1045 * whenever you want to show a notifcation, use this PHP code:
1046 echo Notification::show(array(
1047 'message' => 'Notification text to display',
1048 'class' => 'danger', // or other bootstrap state cues, 'default' if not provided
1049 'dismiss_seconds' => 5, // optional auto-dismiss after x seconds
1050 'dismiss_days' => 7, // optional dismiss for x days if closed by user -- must provide an id
1051 'id' => 'xyz' // optional string to identify the notification -- must use for 'dismiss_days' to work
1052 ));
1053 */
1054 protected static $placeholder_id; /* to force a single notifcation placeholder */
1055
1056 protected function __construct(){} /* to prevent initialization */
1057
1058 public static function placeholder(){
1059 if(self::$placeholder_id) return ''; // output placeholder code only once
1060
1061 self::$placeholder_id = 'notifcation-placeholder-' . rand(10000000, 99999999);
1062
1063 ob_start();
1064 ?>
1065
1066 <div class="notifcation-placeholder" id="<?php echo self::$placeholder_id; ?>"></div>
1067 <script>
1068 $j(function(){
1069 if(window.show_notification != undefined) return;
1070
1071 window.show_notification = function(options){
1072 /* wait till all dependencies ready */
1073 if(window.notifications_ready == undefined){
1074 var op = options;
1075 setTimeout(function(){ /* */ show_notification(op); }, 20);
1076 return;
1077 }
1078
1079 var dismiss_class = '';
1080 var dismiss_icon = '';
1081 var cookie_name = 'hide_notification_' + options.id;
1082 var notif_id = 'notifcation-' + Math.ceil(Math.random() * 1000000);
1083
1084 /* apply provided notficiation id if unique in page */
1085 if(options.id != undefined){
1086 if(!$j('#' + options.id).length) notif_id = options.id;
1087 }
1088
1089 /* notifcation should be hidden? */
1090 if(Cookies.get(cookie_name) != undefined) return;
1091
1092 /* notification should be dismissable? */
1093 if(options.dismiss_seconds > 0 || options.dismiss_days > 0){
1094 dismiss_class = ' alert-dismissible';
1095 dismiss_icon = '<button type="button" class="close" data-dismiss="alert">×</button>';
1096 }
1097
1098 /* remove old dismissed notficiations */
1099 $j('.alert-dismissible.invisible').remove();
1100
1101 /* append notification to notifications container */
1102 $j(
1103 '<div class="alert alert-' + options['class'] + dismiss_class + '" id="' + notif_id + '">' +
1104 dismiss_icon +
1105 options.message +
1106 '</div>'
1107 ).appendTo('#<?php echo self::$placeholder_id; ?>');
1108
1109 var this_notif = $j('#' + notif_id);
1110
1111 /* dismiss after x seconds if requested */
1112 if(options.dismiss_seconds > 0){
1113 setTimeout(function(){ /* */ this_notif.addClass('invisible'); }, options.dismiss_seconds * 1000);
1114 }
1115
1116 /* dismiss for x days if requested and user dismisses it */
1117 if(options.dismiss_days > 0){
1118 var ex_days = options.dismiss_days;
1119 this_notif.on('closed.bs.alert', function(){
1120 /* set a cookie not to show this alert for ex_days */
1121 Cookies.set(cookie_name, '1', { expires: ex_days });
1122 });
1123 }
1124 }
1125
1126 /* cookies library already loaded? */
1127 if(undefined != window.Cookies){
1128 window.notifications_ready = true;
1129 return;
1130 }
1131
1132 /* load cookies library */
1133 $j.ajax({
1134 url: '<?php echo PREPEND_PATH; ?>resources/jscookie/js.cookie.js',
1135 dataType: 'script',
1136 cache: true,
1137 success: function(){ /* */ window.notifications_ready = true; }
1138 });
1139 })
1140 </script>
1141
1142 <?php
1143 $html = ob_get_contents();
1144 ob_end_clean();
1145
1146 return $html;
1147 }
1148
1149 protected static function default_options(&$options){
1150 if(!isset($options['message'])) $options['message'] = 'Notification::show() called without a message!';
1151
1152 if(!isset($options['class'])) $options['class'] = 'default';
1153
1154 if(!isset($options['dismiss_seconds']) || isset($options['dismiss_days'])) $options['dismiss_seconds'] = 0;
1155
1156 if(!isset($options['dismiss_days'])) $options['dismiss_days'] = 0;
1157 if(!isset($options['id'])){
1158 $options['id'] = 0;
1159 $options['dismiss_days'] = 0;
1160 }
1161 }
1162
1163 /**
1164 * @brief Notification::show($options) displays a notification
1165 *
1166 * @param $options assoc array
1167 *
1168 * @return html code for displaying the notifcation
1169 */
1170 public static function show($options = array()){
1171 self::default_options($options);
1172
1173 ob_start();
1174 ?>
1175 <script>
1176 $j(function(){
1177 show_notification(<?php echo json_encode($options); ?>);
1178 })
1179 </script>
1180 <?php
1181 $html = ob_get_contents();
1182 ob_end_clean();
1183
1184 return $html;
1185 }
1186 }
1187 #########################################################
1188 function sendmail($mail){
1189 if(!isset($mail['to'])) return 'No recipient defined';
1190 if(!isEmail($mail['to'])) return 'Invalid recipient email';
1191
1192 $mail['subject'] = isset($mail['subject']) ? $mail['subject'] : '';
1193 $mail['message'] = isset($mail['message']) ? $mail['message'] : '';
1194 $mail['name'] = isset($mail['name']) ? $mail['name'] : '';
1195 $mail['debug'] = isset($mail['debug']) ? min(4, max(0, intval($mail['debug']))) : 0;
1196
1197 $cfg = config('adminConfig');
1198 $smtp = ($cfg['mail_function'] == 'smtp');
1199
1200 if(!class_exists('PHPMailer')){
1201 $curr_dir = dirname(__FILE__);
1202 include("{$curr_dir}/../resources/PHPMailer/class.phpmailer.php");
1203 if($smtp) include("{$curr_dir}/../resources/PHPMailer/class.smtp.php");
1204 }
1205
1206 $pm = new PHPMailer;
1207 $pm->CharSet = datalist_db_encoding;
1208
1209 if($smtp){
1210 $pm->isSMTP();
1211 $pm->SMTPDebug = $mail['debug'];
1212 $pm->Debugoutput = 'html';
1213 $pm->Host = $cfg['smtp_server'];
1214 $pm->Port = $cfg['smtp_port'];
1215 $pm->SMTPAuth = true;
1216 $pm->SMTPSecure = $cfg['smtp_encryption'];
1217 $pm->Username = $cfg['smtp_user'];
1218 $pm->Password = $cfg['smtp_pass'];
1219 }
1220
1221 $pm->setFrom($cfg['senderEmail'], $cfg['senderName']);
1222 $pm->addAddress($mail['to'], $mail['name']);
1223 $pm->Subject = $mail['subject'];
1224
1225 /* if message already contains html tags, don't apply nl2br */
1226 if($mail['message'] == strip_tags($mail['message']))
1227 $mail['message'] = nl2br($mail['message']);
1228
1229 $pm->msgHTML($mail['message'], realpath("{$curr_dir}/.."));
1230
1231 /* if sendmail_handler(&$pm) is defined (in hooks/__global.php) */
1232 if(function_exists('sendmail_handler')) sendmail_handler($pm);
1233
1234 if(!$pm->send()) return $pm->ErrorInfo;
1235
1236 return true;
1237 }
1238 #########################################################
1239 function safe_html($str){
1240 /* if $str has no HTML tags, apply nl2br */
1241 if($str == strip_tags($str)) return nl2br($str);
1242
1243 $hc = new CI_Input();
1244 $hc->charset = datalist_db_encoding;
1245
1246 return $hc->xss_clean($str);
1247 }
1248 #########################################################
1249 function getLoggedGroupID(){
1250 if($_SESSION['memberGroupID']!=''){
1251 return $_SESSION['memberGroupID'];
1252 }else{
1253 if(!setAnonymousAccess()) return false;
1254 return getLoggedGroupID();
1255 }
1256 }
1257 #########################################################
1258 function getLoggedMemberID(){
1259 if($_SESSION['memberID']!=''){
1260 return strtolower($_SESSION['memberID']);
1261 }else{
1262 if(!setAnonymousAccess()) return false;
1263 return getLoggedMemberID();
1264 }
1265 }
1266 #########################################################
1267 function setAnonymousAccess(){
1268 $adminConfig = config('adminConfig');
1269 $anon_group_safe = addslashes($adminConfig['anonymousGroup']);
1270 $anon_user_safe = strtolower(addslashes($adminConfig['anonymousMember']));
1271
1272 $eo = array('silentErrors' => true);
1273
1274 $res = sql("select groupID from membership_groups where name='{$anon_group_safe}'", $eo);
1275 if(!$res){ return false; }
1276 $row = db_fetch_array($res); $anonGroupID = $row[0];
1277
1278 $_SESSION['memberGroupID'] = ($anonGroupID ? $anonGroupID : 0);
1279
1280 $res = sql("select lcase(memberID) from membership_users where lcase(memberID)='{$anon_user_safe}' and groupID='{$anonGroupID}'", $eo);
1281 if(!$res){ return false; }
1282 $row = db_fetch_array($res); $anonMemberID = $row[0];
1283
1284 $_SESSION['memberID'] = ($anonMemberID ? $anonMemberID : 0);
1285
1286 return true;
1287 }
1288 #########################################################
1289 function getMemberInfo($memberID = ''){
1290 static $member_info = array();
1291
1292 if(!$memberID){
1293 $memberID = getLoggedMemberID();
1294 }
1295
1296 // return cached results, if present
1297 if(isset($member_info[$memberID])) return $member_info[$memberID];
1298
1299 $adminConfig = config('adminConfig');
1300 $mi = array();
1301
1302 if($memberID){
1303 $res = sql("select * from membership_users where memberID='" . makeSafe($memberID) . "'", $eo);
1304 if($row = db_fetch_assoc($res)){
1305 $mi = array(
1306 'username' => $memberID,
1307 'groupID' => $row['groupID'],
1308 'group' => sqlValue("select name from membership_groups where groupID='{$row['groupID']}'"),
1309 'admin' => ($adminConfig['adminUsername'] == $memberID ? true : false),
1310 'email' => $row['email'],
1311 'custom' => array(
1312 $row['custom1'],
1313 $row['custom2'],
1314 $row['custom3'],
1315 $row['custom4']
1316 ),
1317 'banned' => ($row['isBanned'] ? true : false),
1318 'approved' => ($row['isApproved'] ? true : false),
1319 'signupDate' => @date('n/j/Y', @strtotime($row['signupDate'])),
1320 'comments' => $row['comments'],
1321 'IP' => $_SERVER['REMOTE_ADDR']
1322 );
1323
1324 // cache results
1325 $member_info[$memberID] = $mi;
1326 }
1327 }
1328
1329 return $mi;
1330 }
1331 #########################################################
1332 function get_group_id($user = ''){
1333 $mi = getMemberInfo($user);
1334 return $mi['groupID'];
1335 }
1336 #########################################################
1337 /**
1338 * @brief Prepares data for a SET or WHERE clause, to be used in an INSERT/UPDATE query
1339 *
1340 * @param [in] $set_array Assoc array of field names => values
1341 * @param [in] $glue optional glue. Set to ' AND ' or ' OR ' if preparing a WHERE clause
1342 * @return SET string
1343 */
1344 function prepare_sql_set($set_array, $glue = ', '){
1345 $fnvs = array();
1346 foreach($set_array as $fn => $fv){
1347 if($fv === null){ $fnvs[] = "{$fn}=NULL"; continue; }
1348
1349 $sfv = makeSafe($fv);
1350 $fnvs[] = "{$fn}='{$sfv}'";
1351 }
1352 return implode($glue, $fnvs);
1353 }
1354 #########################################################
1355 /**
1356 * @brief Inserts a record to the database
1357 *
1358 * @param [in] $tn table name where the record would be inserted
1359 * @param [in] $set_array Assoc array of field names => values to be inserted
1360 * @return boolean indicating success/failure
1361 */
1362 function insert($tn, $set_array){
1363 $set = prepare_sql_set($set_array);
1364 if(!count($set)) return false;
1365
1366 return sql("INSERT INTO `{$tn}` SET {$set}", $eo);
1367 }
1368 #########################################################
1369 /**
1370 * @brief Updates a record in the database
1371 *
1372 * @param [in] $tn table name where the record would be inserted
1373 * @param [in] $set_array Assoc array of field names => values to be inserted
1374 * @param [in] $where_array Assoc array of field names => values used to build the WHERE clause
1375 * @return boolean indicating success/failure
1376 */
1377 function update($tn, $set_array, $where_array){
1378 $set = prepare_sql_set($set_array);
1379 if(!count($set)) return false;
1380
1381 $where = prepare_sql_set($where_array, ' AND ');
1382 if(!$where) $where = '1=1';
1383
1384 return sql("UPDATE `{$tn}` SET {$set} WHERE {$where}", $eo);
1385 }
1386 #########################################################
1387 /**
1388 * @brief Set/update the owner of given record
1389 *
1390 * @param [in] $tn name of table
1391 * @param [in] $pk primary key value
1392 * @param [in] $user username to set as owner
1393 * @return boolean indicating success/failure
1394 */
1395 function set_record_owner($tn, $pk, $user){
1396 $fields = array(
1397 'memberID' => strtolower($user),
1398 'dateUpdated' => time(),
1399 'groupID' => get_group_id($user)
1400 );
1401
1402 $where_array = array('tableName' => $tn, 'pkValue' => $pk);
1403 $where = prepare_sql_set($where_array, ' AND ');
1404 if(!$where) return false;
1405
1406 /* do we have an ownership record? */
1407 $existing_owner = sqlValue("select LCASE(memberID) from membership_userrecords where {$where}");
1408 if($existing_owner == $user) return true; // owner already set to $user
1409
1410 /* update owner */
1411 if($existing_owner){
1412 $res = update('membership_userrecords', $fields, $where_array);
1413 return ($res ? true : false);
1414 }
1415
1416 /* add new ownership record */
1417 $fields = array_merge($fields, $where_array, array('dateAdded' => time()));
1418 $res = insert('membership_userrecords', $fields);
1419 return ($res ? true : false);
1420 }
1421 #########################################################
1422 /**
1423 * @brief get date/time format string for use in different cases.
1424 *
1425 * @param [in] $destination string, one of these: 'php' (see date function), 'mysql', 'moment'
1426 * @param [in] $datetime string, one of these: 'd' = date, 't' = time, 'dt' = both
1427 * @return string
1428 */
1429 function app_datetime_format($destination = 'php', $datetime = 'd'){
1430 switch(strtolower($destination)){
1431 case 'mysql':
1432 $date = '%m/%d/%Y';
1433 $time = '%h:%i:%s %p';
1434 break;
1435 case 'moment':
1436 $date = 'MM/DD/YYYY';
1437 $time = 'hh:mm:ss A';
1438 break;
1439 default: // php
1440 $date = 'm/d/Y';
1441 $time = 'h:i:s A';
1442 }
1443
1444 $datetime = strtolower($datetime);
1445 if($datetime == 'dt' || $datetime == 'td') return "{$date} {$time}";
1446 if($datetime == 't') return $time;
1447 return $date;
1448 }
1449 #########################################################
1450 /**
1451 * @param [in] $app_datetime string, a datetime formatted in app-specific format
1452 * @return string, mysql-formatted datetime, 'yyyy-mm-dd H:i:s', or empty string on error
1453 */
1454 function mysql_datetime($app_datetime, $date_format = null, $time_format = null){
1455 $app_datetime = trim($app_datetime);
1456
1457 if($date_format === null) $date_format = app_datetime_format('php', 'd');
1458 $date_separator = $date_format[1];
1459 if($time_format === null) $time_format = app_datetime_format('php', 't');
1460 $time24 = (strpos($time_format, 'H') !== false); // true if $time_format is 24hr rather than 12
1461
1462 $date_regex = str_replace(
1463 array('Y', 'm', 'd', '/', '.'),
1464 array('([0-9]{4})', '(1[012]|0?[1-9])', '([12][0-9]|3[01]|0?[1-9])', '\/', '\.'),
1465 $date_format
1466 );
1467
1468 $time_regex = str_replace(
1469 array('H', 'h', ':i', ':s'),
1470 array(
1471 '(1[0-9]|2[0-3]|0?[0-9])',
1472 '(1[012]|0?[0-9])',
1473 '(:([1-5][0-9]|0?[0-9]))',
1474 '(:([1-5][0-9]|0?[0-9]))?'
1475 ),
1476 $time_format
1477 );
1478 if(stripos($time_regex, ' a'))
1479 $time_regex = str_replace(array(' a', ' A'), '\s*(am|pm|a|p)?', $time_regex);
1480 else
1481 $time_regex = str_replace(array('a', 'A'), '\s*(am|pm|a|p)?', $time_regex);
1482
1483 // extract date and time
1484 $time = '';
1485 $mat = array();
1486 $regex = "/^({$date_regex})(\s+{$time_regex})?$/i";
1487 $valid_dt = preg_match($regex, $app_datetime, $mat);
1488 if(!$valid_dt || count($mat) < 5) return ''; // invlaid datetime
1489 // if we have a time, get it and change 'a' or 'p' at the end to 'am'/'pm'
1490 if(count($mat) >= 8) $time = preg_replace('/(a|p)$/i', '$1m', trim($mat[5]));
1491
1492 // extract date elements from regex match, given 1st 2 items are full string and full date
1493 $date_order = str_replace($date_separator, '', $date_format);
1494 $day = $mat[stripos($date_order, 'd') + 2];
1495 $month = $mat[stripos($date_order, 'm') + 2];
1496 $year = $mat[stripos($date_order, 'y') + 2];
1497
1498 // convert time to 24hr format if necessary
1499 if($time && !$time24) $time = date('H:i:s', strtotime("2000-01-01 {$time}"));
1500
1501 $mysql_datetime = trim("{$year}-{$month}-{$day} {$time}");
1502
1503 // strtotime handles dates between 1902 and 2037 only
1504 // so we need another test date for dates outside this range ...
1505 $test = $mysql_datetime;
1506 if($year < 1902 || $year > 2037) $test = str_replace($year, '2000', $mysql_datetime);
1507
1508 return (strtotime($test) ? $mysql_datetime : '');
1509 }
1510 #########################################################
1511 /**
1512 * @param [in] $mysql_datetime string, Mysql-formatted datetime
1513 * @param [in] $datetime string, one of these: 'd' = date, 't' = time, 'dt' = both
1514 * @return string, app-formatted datetime, or empty string on error
1515 *
1516 * @details works for formatting date, time and datetime, based on 2nd param
1517 */
1518 function app_datetime($mysql_datetime, $datetime = 'd'){
1519 $pyear = $myear = substr($mysql_datetime, 0, 4);
1520
1521 // strtotime handles dates between 1902 and 2037 only
1522 // so we need a temp date for dates outside this range ...
1523 if($myear < 1902 || $myear > 2037) $pyear = 2000;
1524 $mysql_datetime = str_replace($myear, $pyear, $mysql_datetime);
1525
1526 $ts = strtotime($mysql_datetime);
1527 if(!$ts) return '';
1528
1529 $pdate = date(app_datetime_format('php', $datetime), $ts);
1530 return str_replace($pyear, $myear, $pdate);
1531 }
1532 #########################################################
1533 /**
1534 * @brief converts string from app-configured encoding to utf8
1535 *
1536 * @param [in] $str string to convert to utf8
1537 * @return utf8-encoded string
1538 *
1539 * @details if the constant 'datalist_db_encoding' is not defined, original string is returned
1540 */
1541 function to_utf8($str) {
1542 if(!defined('datalist_db_encoding')) return $str;
1543 if(datalist_db_encoding == 'UTF-8') return $str;
1544 return iconv(datalist_db_encoding, 'UTF-8', $str);
1545 }
1546 #########################################################
1547 /**
1548 * @brief converts string from utf8 to app-configured encoding
1549 *
1550 * @param [in] $str string to convert from utf8
1551 * @return utf8-decoded string
1552 *
1553 * @details if the constant 'datalist_db_encoding' is not defined, original string is returned
1554 */
1555 function from_utf8($str) {
1556 if(!defined('datalist_db_encoding')) return $str;
1557 if(datalist_db_encoding == 'UTF-8') return $str;
1558 return iconv('UTF-8', datalist_db_encoding, $str);
1559 }
2 ########################################################################
3 /*
4 ~~~~~~ LIST OF FUNCTIONS ~~~~~~
5 getTableList() -- returns an associative array of all tables in this application in the format tableName=>tableCaption
6 getThumbnailSpecs($tableName, $fieldName, $view) -- returns an associative array specifying the width, height and identifier of the thumbnail file.
7 createThumbnail($img, $specs) -- $specs is an array as returned by getThumbnailSpecs(). Returns true on success, false on failure.
8 makeSafe($string)
9 checkPermissionVal($pvn)
10 sql($statment, $o)
11 sqlValue($statment)
12 getLoggedAdmin()
13 checkUser($username, $password)
14 logOutUser()
15 getPKFieldName($tn)
16 getCSVData($tn, $pkValue, $stripTag=true)
17 errorMsg($msg)
18 redirect($URL, $absolute=FALSE)
19 htmlRadioGroup($name, $arrValue, $arrCaption, $selectedValue, $selClass="", $class="", $separator="<br>")
20 htmlSelect($name, $arrValue, $arrCaption, $selectedValue, $class="", $selectedClass="")
21 htmlSQLSelect($name, $sql, $selectedValue, $class="", $selectedClass="")
22 isEmail($email) -- returns $email if valid or false otherwise.
23 notifyMemberApproval($memberID) -- send an email to member acknowledging his approval by admin, returns false if no mail is sent
24 setupMembership() -- check if membership tables exist or not. If not, create them.
25 thisOr($this_val, $or) -- return $this_val if it has a value, or $or if not.
26 getUploadedFile($FieldName, $MaxSize=0, $FileTypes='csv|txt', $NoRename=false, $dir='')
27 toBytes($val)
28 convertLegacyOptions($CSVList)
29 getValueGivenCaption($query, $caption)
30 undo_magic_quotes($str)
31 time24($t) -- return time in 24h format
32 time12($t) -- return time in 12h format
33 application_url($page) -- return absolute URL of provided page
34 is_ajax() -- return true if this is an ajax request, false otherwise
35 array_trim($arr) -- recursively trim provided value/array
36 is_allowed_username($username, $exception = false) -- returns username if valid and unique, or false otherwise (if exception is provided and same as username, no uniqueness check is performed)
37 csrf_token($validate) -- csrf-proof a form
38 get_plugins() -- scans for installed plugins and returns them in an array ('name', 'title', 'icon' or 'glyphicon', 'admin_path')
39 maintenance_mode($new_status = '') -- retrieves (and optionally sets) maintenance mode status
40 html_attr($str) -- prepare $str to be placed inside an HTML attribute
41 html_attr_tags_ok($str) -- same as html_attr, but allowing HTML tags
42 Request($var) -- class for providing sanitized values of given request variable (->sql, ->attr, ->html, ->url, and ->raw)
43 Notification() -- class for providing a standardized html notifications functionality
44 sendmail($mail) -- sends an email using PHPMailer as specified in the assoc array $mail( ['to', 'name', 'subject', 'message', 'debug'] ) and returns true on success or an error message on failure
45 safe_html($str) -- sanitize HTML strings, and apply nl2br() to non-HTML ones
46 get_tables_info($skip_authentication = false) -- retrieves table properties as a 2D assoc array ['table_name' => ['prop1' => 'val', ..], ..]
47 getLoggedMemberID() -- returns memberID of logged member. If no login, returns anonymous memberID
48 getLoggedGroupID() -- returns groupID of logged member, or anonymous groupID
49 getMemberInfo() -- returns an array containing the currently signed-in member's info
50 get_group_id($user = '') -- returns groupID of given user, or current one if empty
51 prepare_sql_set($set_array, $glue = ', ') -- Prepares data for a SET or WHERE clause, to be used in an INSERT/UPDATE query
52 insert($tn, $set_array) -- Inserts a record specified by $set_array to the given table $tn
53 update($tn, $set_array, $where_array) -- Updates a record identified by $where_array to date specified by $set_array in the given table $tn
54 set_record_owner($tn, $pk, $user) -- Set/update the owner of given record
55 app_datetime_format($destination = 'php', $datetime = 'd') -- get date/time format string for use with one of these: 'php' (see date function), 'mysql', 'moment'. $datetime: 'd' = date, 't' = time, 'dt' = both
56 mysql_datetime($app_datetime) -- converts $app_datetime to mysql-formatted datetime, 'yyyy-mm-dd H:i:s', or empty string on error
57 app_datetime($mysql_datetime, $datetime = 'd') -- converts $mysql_datetime to app-formatted datetime (if 2nd param is 'dt'), or empty string on error
58 to_utf8($str) -- converts string from app-configured encoding to utf8
59 from_utf8($str) -- converts string from utf8 to app-configured encoding
60 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61 */
62 ########################################################################
63 function get_tables_info($skip_authentication = false){
64 static $all_tables = array(), $accessible_tables = array();
65
66 /* return cached results, if found */
67 if(($skip_authentication || getLoggedAdmin()) && count($all_tables)) return $all_tables;
68 if(!$skip_authentication && count($accessible_tables)) return $accessible_tables;
69
70 /* table groups */
71 $tg = array(
72 'None'
73 );
74
75 $all_tables = array(
76 /* ['table_name' => [table props assoc array] */
77 'schools' => array(
78 'Caption' => 'Schools',
79 'Description' => '',
80 'tableIcon' => 'resources/table_icons/building.png',
81 'group' => $tg[0],
82 'homepageShowCount' => 0
83 ),
84 'departments' => array(
85 'Caption' => 'Departments',
86 'Description' => '',
87 'tableIcon' => 'resources/table_icons/chart_organisation.png',
88 'group' => $tg[0],
89 'homepageShowCount' => 0
90 ),
91 'class_time_table' => array(
92 'Caption' => 'Class time table',
93 'Description' => '',
94 'tableIcon' => 'resources/table_icons/blackboard_drawing.png',
95 'group' => $tg[0],
96 'homepageShowCount' => 0
97 ),
98 'exam_time_table' => array(
99 'Caption' => 'Exam time table',
100 'Description' => '',
101 'tableIcon' => 'resources/table_icons/books.png',
102 'group' => $tg[0],
103 'homepageShowCount' => 0
104 ),
105 'personal_time_table' => array(
106 'Caption' => 'Personal time table',
107 'Description' => '',
108 'tableIcon' => 'resources/table_icons/clock_.png',
109 'group' => $tg[0],
110 'homepageShowCount' => 0
111 ),
112 'student_details' => array(
113 'Caption' => 'Student details',
114 'Description' => '',
115 'tableIcon' => 'resources/table_icons/administrator.png',
116 'group' => $tg[0],
117 'homepageShowCount' => 0
118 ),
119 'notices' => array(
120 'Caption' => 'Notices',
121 'Description' => '',
122 'tableIcon' => 'resources/table_icons/clipboard_empty.png',
123 'group' => $tg[0],
124 'homepageShowCount' => 0
125 )
126 );
127
128 if($skip_authentication || getLoggedAdmin()) return $all_tables;
129
130 foreach($all_tables as $tn => $ti){
131 $arrPerm = getTablePermissions($tn);
132 if($arrPerm[0]) $accessible_tables[$tn] = $ti;
133 }
134
135 return $accessible_tables;
136 }
137 #########################################################
138 if(!function_exists('getTableList')){
139 function getTableList($skip_authentication = false){
140 $arrTables = array(
141 'schools' => 'Schools',
142 'departments' => 'Departments',
143 'class_time_table' => 'Class time table',
144 'exam_time_table' => 'Exam time table',
145 'personal_time_table' => 'Personal time table',
146 'student_details' => 'Student details',
147 'notices' => 'Notices'
148 );
149
150 return $arrTables;
151 }
152 }
153 ########################################################################
154 function getThumbnailSpecs($tableName, $fieldName, $view){
155 return FALSE;
156 }
157 ########################################################################
158 function createThumbnail($img, $specs){
159 $w=$specs['width'];
160 $h=$specs['height'];
161 $id=$specs['identifier'];
162 $path=dirname($img);
163
164 // image doesn't exist or inaccessible?
165 if(!$size=@getimagesize($img)) return FALSE;
166
167 // calculate thumbnail size to maintain aspect ratio
168 $ow=$size[0]; // original image width
169 $oh=$size[1]; // original image height
170 $twbh=$h/$oh*$ow; // calculated thumbnail width based on given height
171 $thbw=$w/$ow*$oh; // calculated thumbnail height based on given width
172 if($w && $h){
173 if($twbh>$w) $h=$thbw;
174 if($thbw>$h) $w=$twbh;
175 }elseif($w){
176 $h=$thbw;
177 }elseif($h){
178 $w=$twbh;
179 }else{
180 return FALSE;
181 }
182
183 // dir not writeable?
184 if(!is_writable($path)) return FALSE;
185
186 // GD lib not loaded?
187 if(!function_exists('gd_info')) return FALSE;
188 $gd=gd_info();
189
190 // GD lib older than 2.0?
191 preg_match('/\d/', $gd['GD Version'], $gdm);
192 if($gdm[0]<2) return FALSE;
193
194 // get file extension
195 preg_match('/\.[a-zA-Z]{3,4}$/U', $img, $matches);
196 $ext=strtolower($matches[0]);
197
198 // check if supplied image is supported and specify actions based on file type
199 if($ext=='.gif'){
200 if(!$gd['GIF Create Support']) return FALSE;
201 $thumbFunc='imagegif';
202 }elseif($ext=='.png'){
203 if(!$gd['PNG Support']) return FALSE;
204 $thumbFunc='imagepng';
205 }elseif($ext=='.jpg' || $ext=='.jpe' || $ext=='.jpeg'){
206 if(!$gd['JPG Support'] && !$gd['JPEG Support']) return FALSE;
207 $thumbFunc='imagejpeg';
208 }else{
209 return FALSE;
210 }
211
212 // determine thumbnail file name
213 $ext=$matches[0];
214 $thumb=substr($img, 0, -5).str_replace($ext, $id.$ext, substr($img, -5));
215
216 // if the original image smaller than thumb, then just copy it to thumb
217 if($h>$oh && $w>$ow){
218 return (@copy($img, $thumb) ? TRUE : FALSE);
219 }
220
221 // get image data
222 if(!$imgData=imagecreatefromstring(implode('', file($img)))) return FALSE;
223
224 // finally, create thumbnail
225 $thumbData=imagecreatetruecolor($w, $h);
226
227 //preserve transparency of png and gif images
228 if($thumbFunc=='imagepng'){
229 if(($clr=@imagecolorallocate($thumbData, 0, 0, 0))!=-1){
230 @imagecolortransparent($thumbData, $clr);
231 @imagealphablending($thumbData, false);
232 @imagesavealpha($thumbData, true);
233 }
234 }elseif($thumbFunc=='imagegif'){
235 @imagealphablending($thumbData, false);
236 $transIndex=imagecolortransparent($imgData);
237 if($transIndex>=0){
238 $transClr=imagecolorsforindex($imgData, $transIndex);
239 $transIndex=imagecolorallocatealpha($thumbData, $transClr['red'], $transClr['green'], $transClr['blue'], 127);
240 imagefill($thumbData, 0, 0, $transIndex);
241 }
242 }
243
244 // resize original image into thumbnail
245 if(!imagecopyresampled($thumbData, $imgData, 0, 0 , 0, 0, $w, $h, $ow, $oh)) return FALSE;
246 unset($imgData);
247
248 // gif transparency
249 if($thumbFunc=='imagegif' && $transIndex>=0){
250 imagecolortransparent($thumbData, $transIndex);
251 for($y=0; $y<$h; ++$y)
252 for($x=0; $x<$w; ++$x)
253 if(((imagecolorat($thumbData, $x, $y)>>24) & 0x7F) >= 100) imagesetpixel($thumbData, $x, $y, $transIndex);
254 imagetruecolortopalette($thumbData, true, 255);
255 imagesavealpha($thumbData, false);
256 }
257
258 if(!$thumbFunc($thumbData, $thumb)) return FALSE;
259 unset($thumbData);
260
261 return TRUE;
262 }
263 ########################################################################
264 function makeSafe($string, $is_gpc = true){
265 if($is_gpc) $string = (get_magic_quotes_gpc() ? stripslashes($string) : $string);
266 if(!db_link()){ sql("select 1+1", $eo); }
267
268 // prevent double escaping
269 $na = explode(',', "\x00,\n,\r,',\",\x1a");
270 $escaped = true;
271 $nosc = true; // no special chars exist
272 foreach($na as $ns){
273 $dan = substr_count($string, $ns);
274 $esdan = substr_count($string, "\\{$ns}");
275 if($dan != $esdan) $escaped = false;
276 if($dan) $nosc = false;
277 }
278 if($nosc){
279 // find unescaped \
280 $dan = substr_count($string, '\\');
281 $esdan = substr_count($string, '\\\\');
282 if($dan != $esdan * 2) $escaped = false;
283 }
284
285 return ($escaped ? $string : db_escape($string));
286 }
287 ########################################################################
288 function checkPermissionVal($pvn){
289 // fn to make sure the value in the given POST variable is 0, 1, 2 or 3
290 // if the value is invalid, it default to 0
291 $pvn=intval($_POST[$pvn]);
292 if($pvn!=1 && $pvn!=2 && $pvn!=3){
293 return 0;
294 }else{
295 return $pvn;
296 }
297 }
298 ########################################################################
299 if(!function_exists('sql')){
300 function sql($statment, &$o){
301
302 /*
303 Supported options that can be passed in $o options array (as array keys):
304 'silentErrors': If true, errors will be returned in $o['error'] rather than displaying them on screen and exiting.
305 */
306
307 global $Translation;
308 static $connected = false, $db_link;
309
310 $dbServer = config('dbServer');
311 $dbUsername = config('dbUsername');
312 $dbPassword = config('dbPassword');
313 $dbDatabase = config('dbDatabase');
314
315 ob_start();
316
317 if(!$connected){
318 /****** Connect to MySQL ******/
319 if(!extension_loaded('mysql') && !extension_loaded('mysqli')){
320 $o['error'] = 'PHP is not configured to connect to MySQL on this machine. Please see <a href="http://www.php.net/manual/en/ref.mysql.php">this page</a> for help on how to configure MySQL.';
321 if($o['silentErrors']) return false;
322
323 echo Notification::placeholder();
324 echo Notification::show(array(
325 'message' => $o['error'],
326 'class' => 'danger',
327 'dismiss_seconds' => 7200
328 ));
329 echo ob_get_clean();
330 exit;
331 }
332
333 if(!($db_link = @db_connect($dbServer, $dbUsername, $dbPassword))){
334 $o['error'] = db_error($db_link, true);
335 if($o['silentErrors']) return false;
336
337 echo Notification::placeholder();
338 echo Notification::show(array(
339 'message' => $o['error'],
340 'class' => 'danger',
341 'dismiss_seconds' => 7200
342 ));
343 echo ob_get_clean();
344 exit;
345 }
346
347 /****** Select DB ********/
348 if(!db_select_db($dbDatabase, $db_link)){
349 $o['error'] = db_error($db_link);
350 if($o['silentErrors']) return false;
351
352 echo Notification::placeholder();
353 echo Notification::show(array(
354 'message' => $o['error'],
355 'class' => 'danger',
356 'dismiss_seconds' => 7200
357 ));
358 echo ob_get_clean();
359 exit;
360 }
361
362 $connected = true;
363 }
364
365 if(!$result = @db_query($statment, $db_link)){
366 if(!stristr($statment, "show columns")){
367 // retrieve error codes
368 $errorNum = db_errno($db_link);
369 $errorMsg = htmlspecialchars(db_error($db_link));
370
371 if(getLoggedAdmin()) $errorMsg .= "<pre class=\"ltr\">{$Translation['query:']}\n" . htmlspecialchars($statment) . "</pre><i class=\"text-right\">{$Translation['admin-only info']}</i>";
372
373 if($o['silentErrors']){ $o['error'] = $errorMsg; return false; }
374
375 echo Notification::placeholder();
376 echo Notification::show(array(
377 'message' => $errorMsg,
378 'class' => 'danger',
379 'dismiss_seconds' => 7200
380 ));
381 echo ob_get_clean();
382 exit;
383 }
384 }
385
386 ob_end_clean();
387 return $result;
388 }
389 }
390
391 ########################################################################
392 function sqlValue($statment){
393 // executes a statment that retreives a single data value and returns the value retrieved
394 if(!$res=sql($statment, $eo)){
395 return FALSE;
396 }
397 if(!$row=db_fetch_row($res)){
398 return FALSE;
399 }
400 return $row[0];
401 }
402 ########################################################################
403 function getLoggedAdmin(){
404 // checks session variables to see whether the admin is logged or not
405 // if not, it returns FALSE
406 // if logged, it returns the user id
407
408 $adminConfig = config('adminConfig');
409
410 if($_SESSION['adminUsername']!=''){
411 return $_SESSION['adminUsername'];
412 }elseif($_SESSION['memberID']==$adminConfig['adminUsername']){
413 $_SESSION['adminUsername']=$_SESSION['memberID'];
414 return $_SESSION['adminUsername'];
415 }else{
416 return FALSE;
417 }
418 }
419 ########################################################################
420 function checkUser($username, $password){
421 // checks given username and password for validity
422 // if valid, registers the username in a session and returns true
423 // else, return FALSE and destroys session
424
425 $adminConfig = config('adminConfig');
426 if($username != $adminConfig['adminUsername'] || md5($password) != $adminConfig['adminPassword']){
427 return FALSE;
428 }
429
430 $_SESSION['adminUsername'] = $username;
431 $_SESSION['memberGroupID'] = sqlValue("select groupID from membership_users where memberID='" . makeSafe($username) ."'");
432 $_SESSION['memberID'] = $username;
433 return TRUE;
434 }
435 ########################################################################
436 function logOutUser(){
437 // destroys current session
438 if(isset($_COOKIE[session_name()])){
439 setcookie(session_name(), '', time() - 42000, '/');
440 }
441 if(isset($_COOKIE[session_name() . '_rememberMe'])){
442 setcookie(session_name() . '_rememberMe', '', time() - 42000);
443 }
444 session_destroy();
445 $_SESSION = array();
446 }
447 ########################################################################
448 function getPKFieldName($tn){
449 // get pk field name of given table
450
451 $stn = makeSafe($tn, false);
452 if(!$res = sql("show fields from `$stn`", $eo)){
453 return false;
454 }
455
456 while($row = db_fetch_assoc($res)){
457 if($row['Key'] == 'PRI'){
458 return $row['Field'];
459 }
460 }
461
462 return false;
463 }
464 ########################################################################
465 function getCSVData($tn, $pkValue, $stripTags=true){
466 // get pk field name for given table
467 if(!$pkField=getPKFieldName($tn)){
468 return "";
469 }
470
471 // get a concat string to produce a csv list of field values for given table record
472 if(!$res=sql("show fields from `$tn`", $eo)){
473 return "";
474 }
475 while($row=db_fetch_assoc($res)){
476 $csvFieldList.="`{$row['Field']}`,";
477 }
478 $csvFieldList=substr($csvFieldList, 0, -1);
479
480 $csvData=sqlValue("select CONCAT_WS(', ', $csvFieldList) from `$tn` where `$pkField`='" . makeSafe($pkValue, false) . "'");
481
482 return ($stripTags ? strip_tags($csvData) : $csvData);
483 }
484 ########################################################################
485 function errorMsg($msg){
486 echo "<div class=\"alert alert-danger\">{$msg}</div>";
487 }
488 ########################################################################
489 function redirect($url, $absolute = false){
490 $fullURL = ($absolute ? $url : application_url($url));
491 if(!headers_sent()) header("Location: {$fullURL}");
492
493 echo "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;url={$fullURL}\">";
494 echo "<br><br><a href=\"{$fullURL}\">Click here</a> if you aren't automatically redirected.";
495 exit;
496 }
497 ########################################################################
498 function htmlRadioGroup($name, $arrValue, $arrCaption, $selectedValue, $selClass = "text-primary", $class = "", $separator = "<br>"){
499 if(!is_array($arrValue)) return '';
500
501 ob_start();
502 ?>
503 <div class="radio %%CLASS%%"><label>
504 <input type="radio" name="%%NAME%%" id="%%ID%%" value="%%VALUE%%" %%CHECKED%%> %%LABEL%%
505 </label></div>
506 <?php
507 $template = ob_get_contents();
508 ob_end_clean();
509
510 $out = '';
511 for($i = 0; $i < count($arrValue); $i++){
512 $replacements = array(
513 '%%CLASS%%' => html_attr($arrValue[$i] == $selectedValue ? $selClass :$class),
514 '%%NAME%%' => html_attr($name),
515 '%%ID%%' => html_attr($name . $i),
516 '%%VALUE%%' => html_attr($arrValue[$i]),
517 '%%LABEL%%' => $arrCaption[$i],
518 '%%CHECKED%%' => ($arrValue[$i]==$selectedValue ? " checked" : "")
519 );
520 $out .= str_replace(array_keys($replacements), array_values($replacements), $template);
521 }
522
523 return $out;
524 }
525 ########################################################################
526 function htmlSelect($name, $arrValue, $arrCaption, $selectedValue, $class="", $selectedClass=""){
527 if($selectedClass==""){
528 $selectedClass=$class;
529 }
530 if(is_array($arrValue)){
531 $out="<select name=\"$name\" id=\"$name\">";
532 for($i=0; $i<count($arrValue); $i++){
533 $out.="<option value=\"".$arrValue[$i]."\"".($arrValue[$i]==$selectedValue ? " selected class=\"$class\"" : " class=\"$selectedClass\"").">".$arrCaption[$i]."</option>";
534 }
535 $out.="</select>";
536 }
537 return $out;
538 }
539 ########################################################################
540 function htmlSQLSelect($name, $sql, $selectedValue, $class="", $selectedClass=""){
541 $arrVal[]='';
542 $arrCap[]='';
543 if($res=sql($sql, $eo)){
544 while($row=db_fetch_row($res)){
545 $arrVal[]=$row[0];
546 $arrCap[]=$row[1];
547 }
548 return htmlSelect($name, $arrVal, $arrCap, $selectedValue, $class, $selectedClass);
549 }else{
550 return "";
551 }
552 }
553 ########################################################################
554 function bootstrapSelect($name, $arrValue, $arrCaption, $selectedValue, $class = '', $selectedClass = ''){
555 if($selectedClass == '') $selectedClass = $class;
556
557 $out = "<select class=\"form-control\" name=\"{$name}\" id=\"{$name}\">";
558 if(is_array($arrValue)){
559 for($i = 0; $i < count($arrValue); $i++){
560 $selected = "class=\"{$class}\"";
561 if($arrValue[$i] == $selectedValue) $selected = "selected class=\"{$selectedClass}\"";
562 $out .= "<option value=\"{$arrValue[$i]}\" {$selected}>{$arrCaption[$i]}</option>";
563 }
564 }
565 $out .= '</select>';
566
567 return $out;
568 }
569 ########################################################################
570 function bootstrapSQLSelect($name, $sql, $selectedValue, $class = '', $selectedClass = ''){
571 $arrVal[] = '';
572 $arrCap[] = '';
573 if($res = sql($sql, $eo)){
574 while($row = db_fetch_row($res)){
575 $arrVal[] = $row[0];
576 $arrCap[] = $row[1];
577 }
578 return bootstrapSelect($name, $arrVal, $arrCap, $selectedValue, $class, $selectedClass);
579 }
580
581 return '';
582 }
583 ########################################################################
584 function isEmail($email){
585 if(preg_match('/^([*+!.&#$¦\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,45})$/i', $email)){
586 return $email;
587 }else{
588 return FALSE;
589 }
590 }
591 ########################################################################
592 function notifyMemberApproval($memberID){
593 $adminConfig = config('adminConfig');
594 $memberID = strtolower($memberID);
595
596 $email = sqlValue("select email from membership_users where lcase(memberID)='{$memberID}'");
597
598 return sendmail(array(
599 'to' => $email,
600 'name' => $memberID,
601 'subject' => $adminConfig['approvalSubject'],
602 'message' => nl2br($adminConfig['approvalMessage'])
603 ));
604 }
605 ########################################################################
606 function setupMembership(){
607 // run once per request
608 static $executed = false;
609 if($executed) return;
610 $executed = true;
611
612 /* abort if current page is one of the following exceptions */
613 $exceptions = array('pageEditMember.php', 'membership_passwordReset.php', 'membership_profile.php', 'membership_signup.php', 'pageChangeMemberStatus.php', 'pageDeleteGroup.php', 'pageDeleteMember.php', 'pageEditGroup.php', 'pageEditMemberPermissions.php', 'pageRebuildFields.php', 'pageSettings.php');
614 if(in_array(basename($_SERVER['PHP_SELF']), $exceptions)) return;
615
616 $eo = array('silentErrors' => true);
617
618 $adminConfig = config('adminConfig');
619 $today = @date('Y-m-d');
620
621 $membership_tables = array(
622 'membership_groups' => "CREATE TABLE IF NOT EXISTS membership_groups (groupID int unsigned NOT NULL auto_increment, name varchar(20), description text, allowSignup tinyint, needsApproval tinyint, PRIMARY KEY (groupID)) CHARSET " . mysql_charset,
623 'membership_users' => "CREATE TABLE IF NOT EXISTS membership_users (memberID varchar(20) NOT NULL, passMD5 varchar(40), email varchar(100), signupDate date, groupID int unsigned, isBanned tinyint, isApproved tinyint, custom1 text, custom2 text, custom3 text, custom4 text, comments text, PRIMARY KEY (memberID)) CHARSET " . mysql_charset,
624 'membership_grouppermissions' => "CREATE TABLE IF NOT EXISTS membership_grouppermissions (permissionID int unsigned NOT NULL auto_increment, groupID int, tableName varchar(100), allowInsert tinyint, allowView tinyint NOT NULL DEFAULT '0', allowEdit tinyint NOT NULL DEFAULT '0', allowDelete tinyint NOT NULL DEFAULT '0', PRIMARY KEY (permissionID)) CHARSET " . mysql_charset,
625 'membership_userrecords' => "CREATE TABLE IF NOT EXISTS membership_userrecords (recID bigint unsigned NOT NULL auto_increment, tableName varchar(100), pkValue varchar(255), memberID varchar(20), dateAdded bigint unsigned, dateUpdated bigint unsigned, groupID int, PRIMARY KEY (recID)) CHARSET " . mysql_charset,
626 'membership_userpermissions' => "CREATE TABLE IF NOT EXISTS membership_userpermissions (permissionID int unsigned NOT NULL auto_increment, memberID varchar(20) NOT NULL, tableName varchar(100), allowInsert tinyint, allowView tinyint NOT NULL DEFAULT '0', allowEdit tinyint NOT NULL DEFAULT '0', allowDelete tinyint NOT NULL DEFAULT '0', PRIMARY KEY (permissionID)) CHARSET " . mysql_charset
627 );
628
629 // get db tables
630 $tables = array();
631 $res = sql("show tables", $eo);
632
633 if(!$res){
634 include_once(dirname(__FILE__) . '/../header.php');
635 echo $eo['error'];
636 include_once(dirname(__FILE__) . '/../footer.php');
637 exit;
638 }
639
640 while($row = db_fetch_array($res)) $tables[] = $row[0];
641
642 // check if membership tables exist or not
643 foreach($membership_tables as $tn => $tdef){
644 if(!in_array($tn, $tables)){
645 sql($tdef, $eo);
646 }
647 }
648
649 // check membership_users definition
650 $membership_users = array();
651 $res = sql("show columns from membership_users", $eo);
652 while($row = db_fetch_assoc($res)) $membership_users[$row['Field']] = $row;
653
654 if(!in_array('pass_reset_key', array_keys($membership_users))) @db_query("ALTER TABLE membership_users ADD COLUMN pass_reset_key VARCHAR(100)");
655 if(!in_array('pass_reset_expiry', array_keys($membership_users))) @db_query("ALTER TABLE membership_users ADD COLUMN pass_reset_expiry INT UNSIGNED");
656 if(!$membership_users['groupID']['Key']) @db_query("ALTER TABLE membership_users ADD INDEX groupID (groupID)");
657
658 // create membership indices if not existing
659 $membership_userrecords = array();
660 $res = sql("show keys from membership_userrecords", $eo);
661 while($row = db_fetch_assoc($res)) $membership_userrecords[$row['Key_name']][$row['Seq_in_index']] = $row;
662
663 if(!$membership_userrecords['pkValue'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX pkValue (pkValue)");
664 if(!$membership_userrecords['tableName'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX tableName (tableName)");
665 if(!$membership_userrecords['memberID'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX memberID (memberID)");
666 if(!$membership_userrecords['groupID'][1]) @db_query("ALTER TABLE membership_userrecords ADD INDEX groupID (groupID)");
667 if(!$membership_userrecords['tableName_pkValue'][1] || !$membership_userrecords['tableName_pkValue'][2]) @db_query("ALTER IGNORE TABLE membership_userrecords ADD UNIQUE INDEX tableName_pkValue (tableName, pkValue)");
668
669 // retreive anonymous and admin groups and their permissions
670 $anon_group = $adminConfig['anonymousGroup'];
671 $anon_user = strtolower($adminConfig['anonymousMember']);
672 $admin_group = 'Admins';
673 $admin_user = strtolower($adminConfig['adminUsername']);
674 $groups_permissions = array();
675 $res = sql(
676 "select g.groupID, g.name, gp.tableName, gp.allowInsert, gp.allowView, gp.allowEdit, gp.allowDelete " .
677 "from membership_groups g left join membership_grouppermissions gp on g.groupID=gp.groupID " .
678 "where g.name='" . makeSafe($admin_group) . "' or g.name='" . makeSafe($anon_group) . "' " .
679 "order by g.groupID, gp.tableName", $eo
680 );
681 while($row = db_fetch_assoc($res)) $groups_permissions[] = $row;
682
683 // check anonymous group and user and create if necessary
684 $anon_group_id = false;
685 foreach($groups_permissions as $group){
686 if($group['name'] == $anon_group){
687 $anon_group_id = $group['groupID'];
688 break;
689 }
690 }
691
692 if(!$anon_group_id){
693 sql("insert into membership_groups set name='" . makeSafe($anon_group) . "', allowSignup=0, needsApproval=0, description='Anonymous group created automatically on " . @date("Y-m-d") . "'", $eo);
694 $anon_group_id = db_insert_id();
695 }
696
697 if($anon_group_id){
698 $anon_user_db = sqlValue("select lcase(memberID) from membership_users where lcase(memberID)='" . makeSafe($anon_user) . "' and groupID='{$anon_group_id}'");
699 if(!$anon_user_db || $anon_user_db != $anon_user){
700 sql("delete from membership_users where groupID='{$anon_group_id}'", $eo);
701 sql("insert into membership_users set memberID='" . makeSafe($anon_user) . "', signUpDate='{$today}', groupID='{$anon_group_id}', isBanned=0, isApproved=1, comments='Anonymous member created automatically on {$today}'", $eo);
702 }
703 }
704
705 // check admin group and user and create if necessary
706 $admin_group_id = false;
707 foreach($groups_permissions as $group){
708 if($group['name'] == $admin_group){
709 $admin_group_id = $group['groupID'];
710 break;
711 }
712 }
713
714 if(!$admin_group_id){
715 sql("insert into membership_groups set name='" . makeSafe($admin_group) . "', allowSignup=0, needsApproval=1, description='Admin group created automatically on {$today}'", $eo);
716 $admin_group_id = db_insert_id();
717 }
718
719 if($admin_group_id){
720 // check that admins can access all tables
721 $all_tables = getTableList(true);
722 $tables_ok = $perms_ok = array();
723 foreach($all_tables as $tn => $tc) $tables_ok[$tn] = $perms_ok[$tn] = false;
724
725 foreach($groups_permissions as $group){
726 if($group['name'] == $admin_group){
727 if(isset($tables_ok[$group['tableName']])){
728 $tables_ok[$group['tableName']] = true;
729 if($group['allowInsert'] == 1 && $group['allowDelete'] == 3 && $group['allowEdit'] == 3 && $group['allowView'] == 3){
730 $perms_ok[$group['tableName']] = true;
731 }
732 }
733 }
734 }
735
736 // if any table has no record in Admins permissions, create one for it
737 $grant_sql = array();
738 foreach($tables_ok as $tn => $status){
739 if(!$status) $grant_sql[] = "({$admin_group_id}, '{$tn}')";
740 }
741
742 if(count($grant_sql)){
743 sql("insert into membership_grouppermissions (groupID, tableName) values " . implode(',', $grant_sql), $eo);
744 }
745
746 // check admin permissions and update if necessary
747 $perms_sql = array();
748 foreach($perms_ok as $tn => $status){
749 if(!$status) $perms_sql[] = "'{$tn}'";
750 }
751
752 if(count($perms_sql)){
753 sql("update membership_grouppermissions set allowInsert=1, allowView=3, allowEdit=3, allowDelete=3 where groupID={$admin_group_id} and tableName in (" . implode(',', $perms_sql) . ")", $eo);
754 }
755
756 // check if super admin is stored in the users table and add him if not
757 $admin_user_exists = sqlValue("select count(1) from membership_users where lcase(memberID)='" . makeSafe($admin_user)."' and groupID='{$admin_group_id}'");
758 if(!$admin_user_exists){
759 sql("insert into membership_users set memberID='" . makeSafe($admin_user) . "', passMD5='{$adminConfig['adminPassword']}', email='{$adminConfig['senderEmail']}', signUpDate='{$today}', groupID='{$admin_group_id}', isBanned=0, isApproved=1, comments='Admin member created automatically on {$today}'", $eo);
760 }
761 }
762 }
763
764 ########################################################################
765 function thisOr($this_val, $or = ' '){
766 return ($this_val != '' ? $this_val : $or);
767 }
768 ########################################################################
769 function getUploadedFile($FieldName, $MaxSize=0, $FileTypes='csv|txt', $NoRename=false, $dir=''){
770 $currDir=dirname(__FILE__);
771 if(is_array($_FILES)){
772 $f = $_FILES[$FieldName];
773 }else{
774 return 'Your php settings don\'t allow file uploads.';
775 }
776
777 if(!$MaxSize){
778 $MaxSize=toBytes(ini_get('upload_max_filesize'));
779 }
780
781 if(!is_dir("$currDir/csv")){
782 @mkdir("$currDir/csv");
783 }
784
785 $dir=(is_dir($dir) && is_writable($dir) ? $dir : "$currDir/csv/");
786
787 if($f['error']!=4 && $f['name']!=''){
788 if($f['size']>$MaxSize || $f['error']){
789 return 'File size exceeds maximum allowed of '.intval($MaxSize / 1024).'KB';
790 }
791 if(!preg_match('/\.('.$FileTypes.')$/i', $f['name'], $ft)){
792 return 'File type not allowed. Only these file types are allowed: '.str_replace('|', ', ', $FileTypes);
793 }
794
795 if($NoRename){
796 $n = str_replace(' ', '_', $f['name']);
797 }else{
798 $n = microtime();
799 $n = str_replace(' ', '_', $n);
800 $n = str_replace('0.', '', $n);
801 $n .= $ft[0];
802 }
803
804 if(!@move_uploaded_file($f['tmp_name'], $dir . $n)){
805 return 'Couldn\'t save the uploaded file. Try chmoding the upload folder "'.$dir.'" to 777.';
806 }else{
807 @chmod($dir.$n, 0666);
808 return $dir.$n;
809 }
810 }
811 return 'An error occured while uploading the file. Please try again.';
812 }
813 ########################################################################
814 function toBytes($val){
815 $val = trim($val);
816 $last = strtolower($val{strlen($val)-1});
817 switch($last){
818 // The 'G' modifier is available since PHP 5.1.0
819 case 'g':
820 $val *= 1024;
821 case 'm':
822 $val *= 1024;
823 case 'k':
824 $val *= 1024;
825 }
826
827 return $val;
828 }
829 ########################################################################
830 function convertLegacyOptions($CSVList){
831 $CSVList=str_replace(';;;', ';||', $CSVList);
832 $CSVList=str_replace(';;', '||', $CSVList);
833 return $CSVList;
834 }
835 ########################################################################
836 function getValueGivenCaption($query, $caption){
837 if(!preg_match('/select\s+(.*?)\s*,\s*(.*?)\s+from\s+(.*?)\s+order by.*/i', $query, $m)){
838 if(!preg_match('/select\s+(.*?)\s*,\s*(.*?)\s+from\s+(.*)/i', $query, $m)){
839 return '';
840 }
841 }
842
843 // get where clause if present
844 if(preg_match('/\s+from\s+(.*?)\s+where\s+(.*?)\s+order by.*/i', $query, $mw)){
845 $where="where ($mw[2]) AND";
846 $m[3]=$mw[1];
847 }else{
848 $where='where';
849 }
850
851 $caption=makeSafe($caption);
852 return sqlValue("SELECT $m[1] FROM $m[3] $where $m[2]='$caption'");
853 }
854 ########################################################################
855 function undo_magic_quotes($str){
856 return (get_magic_quotes_gpc() ? stripslashes($str) : $str);
857 }
858 ########################################################################
859 function time24($t = false){
860 if($t === false) $t = date('Y-m-d H:i:s'); // time now if $t not passed
861 elseif(!$t) return ''; // empty string if $t empty
862 return date('H:i:s', strtotime($t));
863 }
864 ########################################################################
865 function time12($t = false){
866 if($t === false) $t = date('Y-m-d H:i:s'); // time now if $t not passed
867 elseif(!$t) return ''; // empty string if $t empty
868 return date('h:i:s A', strtotime($t));
869 }
870 ########################################################################
871 function application_url($page = '', $s = false){
872 if($s === false) $s = $_SERVER;
873 $ssl = (!empty($s['HTTPS']) && $s['HTTPS'] == 'on');
874 $http = ($ssl ? 'https:' : 'http:');
875 $port = $s['SERVER_PORT'];
876 $port = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port;
877 $host = (isset($s['HTTP_HOST']) ? $s['HTTP_HOST'] : $s['SERVER_NAME'] . $port);
878 $uri = dirname($s['SCRIPT_NAME']);
879
880 /* app folder name (without the ending /admin part) */
881 $app_folder_is_admin = false;
882 $app_folder = substr(dirname(__FILE__), 0, -6);
883 if(substr($app_folder, -6, 6) == '/admin' || substr($app_folder, -6, 6) == '\\admin')
884 $app_folder_is_admin = true;
885
886 if(substr($uri, -12, 12) == '/admin/admin') $uri = substr($uri, 0, -6);
887 elseif(substr($uri, -6, 6) == '/admin' && !$app_folder_is_admin) $uri = substr($uri, 0, -6);
888 elseif($uri == '/' || $uri == '\\') $uri = '';
889
890 return "{$http}//{$host}{$uri}/{$page}";
891 }
892 ########################################################################
893 function is_ajax(){
894 return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
895 }
896 ########################################################################
897 function array_trim($arr){
898 if(!is_array($arr)) return trim($arr);
899 return array_map('array_trim', $arr);
900 }
901 ########################################################################
902 function is_allowed_username($username, $exception = false){
903 $username = trim(strtolower($username));
904 if(!preg_match('/^[a-z0-9][a-z0-9 _.@]{3,19}$/', $username) || preg_match('/(@@| |\.\.|___)/', $username)) return false;
905
906 if($username == $exception) return $username;
907
908 if(sqlValue("select count(1) from membership_users where lcase(memberID)='{$username}'")) return false;
909 return $username;
910 }
911 ########################################################################
912 /*
913 if called without parameters, looks for a non-expired token in the user's session (or creates one if
914 none found) and returns html code to insert into the form to be protected.
915
916 if set to true, validates token sent in $_REQUEST against that stored in the session
917 and returns true if valid or false if invalid, absent or expired.
918
919 usage:
920 1. in a new form that needs csrf proofing: echo csrf_token();
921 >> in case of ajax requests and similar, retrieve token directly
922 by calling csrf_token(false, true);
923 2. when validating a submitted form: if(!csrf_token(true)){ reject_submission_somehow(); }
924 */
925 function csrf_token($validate = false, $token_only = false){
926 $token_age = 60 * 60;
927 /* retrieve token from session */
928 $csrf_token = (isset($_SESSION['csrf_token']) ? $_SESSION['csrf_token'] : false);
929 $csrf_token_expiry = (isset($_SESSION['csrf_token_expiry']) ? $_SESSION['csrf_token_expiry'] : false);
930
931 if(!$validate){
932 /* create a new token if necessary */
933 if($csrf_token_expiry < time() || !$csrf_token){
934 $csrf_token = md5(uniqid(rand(), true));
935 $csrf_token_expiry = time() + $token_age;
936 $_SESSION['csrf_token'] = $csrf_token;
937 $_SESSION['csrf_token_expiry'] = $csrf_token_expiry;
938 }
939
940 if($token_only) return $csrf_token;
941 return '<input type="hidden" id="csrf_token" name="csrf_token" value="' . $csrf_token . '">';
942 }
943
944 /* validate submitted token */
945 $user_token = (isset($_REQUEST['csrf_token']) ? $_REQUEST['csrf_token'] : false);
946 if($csrf_token_expiry < time() || !$user_token || $user_token != $csrf_token){
947 return false;
948 }
949
950 return true;
951 }
952 ########################################################################
953 function get_plugins(){
954 $plugins = array();
955 $plugins_path = dirname(__FILE__) . '/../plugins/';
956
957 if(!is_dir($plugins_path)) return $plugins;
958
959 $pd = dir($plugins_path);
960 while(false !== ($plugin = $pd->read())){
961 if(!is_dir($plugins_path . $plugin) || in_array($plugin, array('projects', 'plugins-resources', '.', '..'))) continue;
962
963 $info_file = "{$plugins_path}{$plugin}/plugin-info.json";
964 if(!is_file($info_file)) continue;
965
966 $plugins[] = json_decode(file_get_contents($info_file), true);
967 $plugins[count($plugins) - 1]['admin_path'] = "../plugins/{$plugin}";
968 }
969 $pd->close();
970
971 return $plugins;
972 }
973 ########################################################################
974 function maintenance_mode($new_status = ''){
975 $maintenance_file = dirname(__FILE__) . '/.maintenance';
976
977 if($new_status === true){
978 /* turn on maintenance mode */
979 @touch($maintenance_file);
980 }elseif($new_status === false){
981 /* turn off maintenance mode */
982 @unlink($maintenance_file);
983 }
984
985 /* return current maintenance mode status */
986 return is_file($maintenance_file);
987 }
988 ########################################################################
989 function handle_maintenance($echo = false){
990 if(!maintenance_mode()) return;
991
992 global $Translation;
993 $adminConfig = config('adminConfig');
994
995 $admin = getLoggedAdmin();
996 if($admin){
997 return ($echo ? '<div class="alert alert-danger" style="margin: 5em auto -5em;"><b>' . $Translation['maintenance mode admin notification'] . '</b></div>' : '');
998 }
999
1000 if(!$echo) exit;
1001
1002 exit('<div class="alert alert-danger" style="margin-top: 5em; font-size: 2em;"><i class="glyphicon glyphicon-exclamation-sign"></i> ' . $adminConfig['maintenance_mode_message'] . '</div>');
1003 }
1004 #########################################################
1005 function html_attr($str){
1006 if(version_compare(PHP_VERSION, '5.2.3') >= 0) return htmlspecialchars($str, ENT_QUOTES, datalist_db_encoding, false);
1007 return htmlspecialchars($str, ENT_QUOTES, datalist_db_encoding);
1008 }
1009 #########################################################
1010 function html_attr_tags_ok($str){
1011 // use this instead of html_attr() if you don't want html tags to be escaped
1012 $new_str = html_attr($str);
1013 return str_replace(array('<', '>'), array('<', '>'), $new_str);
1014 }
1015 #########################################################
1016 class Request{
1017 var $sql, $url, $attr, $html, $raw;
1018
1019 function __construct($var, $filter = false){
1020 $this->Request($var, $filter);
1021 }
1022
1023 function Request($var, $filter = false){
1024 $unsafe = (isset($_REQUEST[$var]) ? $_REQUEST[$var] : '');
1025 if(get_magic_quotes_gpc()) $unsafe = stripslashes($unsafe);
1026
1027 if($filter){
1028 $unsafe = call_user_func($filter, $unsafe);
1029 }
1030
1031 $this->sql = makeSafe($unsafe, false);
1032 $this->url = urlencode($unsafe);
1033 $this->attr = html_attr($unsafe);
1034 $this->html = html_attr($unsafe);
1035 $this->raw = $unsafe;
1036 }
1037 }
1038 #########################################################
1039 class Notification{
1040 /*
1041 Usage:
1042 * in the main document, initiate notifications support using this PHP code:
1043 echo Notification::placeholder();
1044
1045 * whenever you want to show a notifcation, use this PHP code:
1046 echo Notification::show(array(
1047 'message' => 'Notification text to display',
1048 'class' => 'danger', // or other bootstrap state cues, 'default' if not provided
1049 'dismiss_seconds' => 5, // optional auto-dismiss after x seconds
1050 'dismiss_days' => 7, // optional dismiss for x days if closed by user -- must provide an id
1051 'id' => 'xyz' // optional string to identify the notification -- must use for 'dismiss_days' to work
1052 ));
1053 */
1054 protected static $placeholder_id; /* to force a single notifcation placeholder */
1055
1056 protected function __construct(){} /* to prevent initialization */
1057
1058 public static function placeholder(){
1059 if(self::$placeholder_id) return ''; // output placeholder code only once
1060
1061 self::$placeholder_id = 'notifcation-placeholder-' . rand(10000000, 99999999);
1062
1063 ob_start();
1064 ?>
1065
1066 <div class="notifcation-placeholder" id="<?php echo self::$placeholder_id; ?>"></div>
1067 <script>
1068 $j(function(){
1069 if(window.show_notification != undefined) return;
1070
1071 window.show_notification = function(options){
1072 /* wait till all dependencies ready */
1073 if(window.notifications_ready == undefined){
1074 var op = options;
1075 setTimeout(function(){ /* */ show_notification(op); }, 20);
1076 return;
1077 }
1078
1079 var dismiss_class = '';
1080 var dismiss_icon = '';
1081 var cookie_name = 'hide_notification_' + options.id;
1082 var notif_id = 'notifcation-' + Math.ceil(Math.random() * 1000000);
1083
1084 /* apply provided notficiation id if unique in page */
1085 if(options.id != undefined){
1086 if(!$j('#' + options.id).length) notif_id = options.id;
1087 }
1088
1089 /* notifcation should be hidden? */
1090 if(Cookies.get(cookie_name) != undefined) return;
1091
1092 /* notification should be dismissable? */
1093 if(options.dismiss_seconds > 0 || options.dismiss_days > 0){
1094 dismiss_class = ' alert-dismissible';
1095 dismiss_icon = '<button type="button" class="close" data-dismiss="alert">×</button>';
1096 }
1097
1098 /* remove old dismissed notficiations */
1099 $j('.alert-dismissible.invisible').remove();
1100
1101 /* append notification to notifications container */
1102 $j(
1103 '<div class="alert alert-' + options['class'] + dismiss_class + '" id="' + notif_id + '">' +
1104 dismiss_icon +
1105 options.message +
1106 '</div>'
1107 ).appendTo('#<?php echo self::$placeholder_id; ?>');
1108
1109 var this_notif = $j('#' + notif_id);
1110
1111 /* dismiss after x seconds if requested */
1112 if(options.dismiss_seconds > 0){
1113 setTimeout(function(){ /* */ this_notif.addClass('invisible'); }, options.dismiss_seconds * 1000);
1114 }
1115
1116 /* dismiss for x days if requested and user dismisses it */
1117 if(options.dismiss_days > 0){
1118 var ex_days = options.dismiss_days;
1119 this_notif.on('closed.bs.alert', function(){
1120 /* set a cookie not to show this alert for ex_days */
1121 Cookies.set(cookie_name, '1', { expires: ex_days });
1122 });
1123 }
1124 }
1125
1126 /* cookies library already loaded? */
1127 if(undefined != window.Cookies){
1128 window.notifications_ready = true;
1129 return;
1130 }
1131
1132 /* load cookies library */
1133 $j.ajax({
1134 url: '<?php echo PREPEND_PATH; ?>resources/jscookie/js.cookie.js',
1135 dataType: 'script',
1136 cache: true,
1137 success: function(){ /* */ window.notifications_ready = true; }
1138 });
1139 })
1140 </script>
1141
1142 <?php
1143 $html = ob_get_contents();
1144 ob_end_clean();
1145
1146 return $html;
1147 }
1148
1149 protected static function default_options(&$options){
1150 if(!isset($options['message'])) $options['message'] = 'Notification::show() called without a message!';
1151
1152 if(!isset($options['class'])) $options['class'] = 'default';
1153
1154 if(!isset($options['dismiss_seconds']) || isset($options['dismiss_days'])) $options['dismiss_seconds'] = 0;
1155
1156 if(!isset($options['dismiss_days'])) $options['dismiss_days'] = 0;
1157 if(!isset($options['id'])){
1158 $options['id'] = 0;
1159 $options['dismiss_days'] = 0;
1160 }
1161 }
1162
1163 /**
1164 * @brief Notification::show($options) displays a notification
1165 *
1166 * @param $options assoc array
1167 *
1168 * @return html code for displaying the notifcation
1169 */
1170 public static function show($options = array()){
1171 self::default_options($options);
1172
1173 ob_start();
1174 ?>
1175 <script>
1176 $j(function(){
1177 show_notification(<?php echo json_encode($options); ?>);
1178 })
1179 </script>
1180 <?php
1181 $html = ob_get_contents();
1182 ob_end_clean();
1183
1184 return $html;
1185 }
1186 }
1187 #########################################################
1188 function sendmail($mail){
1189 if(!isset($mail['to'])) return 'No recipient defined';
1190 if(!isEmail($mail['to'])) return 'Invalid recipient email';
1191
1192 $mail['subject'] = isset($mail['subject']) ? $mail['subject'] : '';
1193 $mail['message'] = isset($mail['message']) ? $mail['message'] : '';
1194 $mail['name'] = isset($mail['name']) ? $mail['name'] : '';
1195 $mail['debug'] = isset($mail['debug']) ? min(4, max(0, intval($mail['debug']))) : 0;
1196
1197 $cfg = config('adminConfig');
1198 $smtp = ($cfg['mail_function'] == 'smtp');
1199
1200 if(!class_exists('PHPMailer')){
1201 $curr_dir = dirname(__FILE__);
1202 include("{$curr_dir}/../resources/PHPMailer/class.phpmailer.php");
1203 if($smtp) include("{$curr_dir}/../resources/PHPMailer/class.smtp.php");
1204 }
1205
1206 $pm = new PHPMailer;
1207 $pm->CharSet = datalist_db_encoding;
1208
1209 if($smtp){
1210 $pm->isSMTP();
1211 $pm->SMTPDebug = $mail['debug'];
1212 $pm->Debugoutput = 'html';
1213 $pm->Host = $cfg['smtp_server'];
1214 $pm->Port = $cfg['smtp_port'];
1215 $pm->SMTPAuth = true;
1216 $pm->SMTPSecure = $cfg['smtp_encryption'];
1217 $pm->Username = $cfg['smtp_user'];
1218 $pm->Password = $cfg['smtp_pass'];
1219 }
1220
1221 $pm->setFrom($cfg['senderEmail'], $cfg['senderName']);
1222 $pm->addAddress($mail['to'], $mail['name']);
1223 $pm->Subject = $mail['subject'];
1224
1225 /* if message already contains html tags, don't apply nl2br */
1226 if($mail['message'] == strip_tags($mail['message']))
1227 $mail['message'] = nl2br($mail['message']);
1228
1229 $pm->msgHTML($mail['message'], realpath("{$curr_dir}/.."));
1230
1231 /* if sendmail_handler(&$pm) is defined (in hooks/__global.php) */
1232 if(function_exists('sendmail_handler')) sendmail_handler($pm);
1233
1234 if(!$pm->send()) return $pm->ErrorInfo;
1235
1236 return true;
1237 }
1238 #########################################################
1239 function safe_html($str){
1240 /* if $str has no HTML tags, apply nl2br */
1241 if($str == strip_tags($str)) return nl2br($str);
1242
1243 $hc = new CI_Input();
1244 $hc->charset = datalist_db_encoding;
1245
1246 return $hc->xss_clean($str);
1247 }
1248 #########################################################
1249 function getLoggedGroupID(){
1250 if($_SESSION['memberGroupID']!=''){
1251 return $_SESSION['memberGroupID'];
1252 }else{
1253 if(!setAnonymousAccess()) return false;
1254 return getLoggedGroupID();
1255 }
1256 }
1257 #########################################################
1258 function getLoggedMemberID(){
1259 if($_SESSION['memberID']!=''){
1260 return strtolower($_SESSION['memberID']);
1261 }else{
1262 if(!setAnonymousAccess()) return false;
1263 return getLoggedMemberID();
1264 }
1265 }
1266 #########################################################
1267 function setAnonymousAccess(){
1268 $adminConfig = config('adminConfig');
1269 $anon_group_safe = addslashes($adminConfig['anonymousGroup']);
1270 $anon_user_safe = strtolower(addslashes($adminConfig['anonymousMember']));
1271
1272 $eo = array('silentErrors' => true);
1273
1274 $res = sql("select groupID from membership_groups where name='{$anon_group_safe}'", $eo);
1275 if(!$res){ return false; }
1276 $row = db_fetch_array($res); $anonGroupID = $row[0];
1277
1278 $_SESSION['memberGroupID'] = ($anonGroupID ? $anonGroupID : 0);
1279
1280 $res = sql("select lcase(memberID) from membership_users where lcase(memberID)='{$anon_user_safe}' and groupID='{$anonGroupID}'", $eo);
1281 if(!$res){ return false; }
1282 $row = db_fetch_array($res); $anonMemberID = $row[0];
1283
1284 $_SESSION['memberID'] = ($anonMemberID ? $anonMemberID : 0);
1285
1286 return true;
1287 }
1288 #########################################################
1289 function getMemberInfo($memberID = ''){
1290 static $member_info = array();
1291
1292 if(!$memberID){
1293 $memberID = getLoggedMemberID();
1294 }
1295
1296 // return cached results, if present
1297 if(isset($member_info[$memberID])) return $member_info[$memberID];
1298
1299 $adminConfig = config('adminConfig');
1300 $mi = array();
1301
1302 if($memberID){
1303 $res = sql("select * from membership_users where memberID='" . makeSafe($memberID) . "'", $eo);
1304 if($row = db_fetch_assoc($res)){
1305 $mi = array(
1306 'username' => $memberID,
1307 'groupID' => $row['groupID'],
1308 'group' => sqlValue("select name from membership_groups where groupID='{$row['groupID']}'"),
1309 'admin' => ($adminConfig['adminUsername'] == $memberID ? true : false),
1310 'email' => $row['email'],
1311 'custom' => array(
1312 $row['custom1'],
1313 $row['custom2'],
1314 $row['custom3'],
1315 $row['custom4']
1316 ),
1317 'banned' => ($row['isBanned'] ? true : false),
1318 'approved' => ($row['isApproved'] ? true : false),
1319 'signupDate' => @date('n/j/Y', @strtotime($row['signupDate'])),
1320 'comments' => $row['comments'],
1321 'IP' => $_SERVER['REMOTE_ADDR']
1322 );
1323
1324 // cache results
1325 $member_info[$memberID] = $mi;
1326 }
1327 }
1328
1329 return $mi;
1330 }
1331 #########################################################
1332 function get_group_id($user = ''){
1333 $mi = getMemberInfo($user);
1334 return $mi['groupID'];
1335 }
1336 #########################################################
1337 /**
1338 * @brief Prepares data for a SET or WHERE clause, to be used in an INSERT/UPDATE query
1339 *
1340 * @param [in] $set_array Assoc array of field names => values
1341 * @param [in] $glue optional glue. Set to ' AND ' or ' OR ' if preparing a WHERE clause
1342 * @return SET string
1343 */
1344 function prepare_sql_set($set_array, $glue = ', '){
1345 $fnvs = array();
1346 foreach($set_array as $fn => $fv){
1347 if($fv === null){ $fnvs[] = "{$fn}=NULL"; continue; }
1348
1349 $sfv = makeSafe($fv);
1350 $fnvs[] = "{$fn}='{$sfv}'";
1351 }
1352 return implode($glue, $fnvs);
1353 }
1354 #########################################################
1355 /**
1356 * @brief Inserts a record to the database
1357 *
1358 * @param [in] $tn table name where the record would be inserted
1359 * @param [in] $set_array Assoc array of field names => values to be inserted
1360 * @return boolean indicating success/failure
1361 */
1362 function insert($tn, $set_array){
1363 $set = prepare_sql_set($set_array);
1364 if(!count($set)) return false;
1365
1366 return sql("INSERT INTO `{$tn}` SET {$set}", $eo);
1367 }
1368 #########################################################
1369 /**
1370 * @brief Updates a record in the database
1371 *
1372 * @param [in] $tn table name where the record would be inserted
1373 * @param [in] $set_array Assoc array of field names => values to be inserted
1374 * @param [in] $where_array Assoc array of field names => values used to build the WHERE clause
1375 * @return boolean indicating success/failure
1376 */
1377 function update($tn, $set_array, $where_array){
1378 $set = prepare_sql_set($set_array);
1379 if(!count($set)) return false;
1380
1381 $where = prepare_sql_set($where_array, ' AND ');
1382 if(!$where) $where = '1=1';
1383
1384 return sql("UPDATE `{$tn}` SET {$set} WHERE {$where}", $eo);
1385 }
1386 #########################################################
1387 /**
1388 * @brief Set/update the owner of given record
1389 *
1390 * @param [in] $tn name of table
1391 * @param [in] $pk primary key value
1392 * @param [in] $user username to set as owner
1393 * @return boolean indicating success/failure
1394 */
1395 function set_record_owner($tn, $pk, $user){
1396 $fields = array(
1397 'memberID' => strtolower($user),
1398 'dateUpdated' => time(),
1399 'groupID' => get_group_id($user)
1400 );
1401
1402 $where_array = array('tableName' => $tn, 'pkValue' => $pk);
1403 $where = prepare_sql_set($where_array, ' AND ');
1404 if(!$where) return false;
1405
1406 /* do we have an ownership record? */
1407 $existing_owner = sqlValue("select LCASE(memberID) from membership_userrecords where {$where}");
1408 if($existing_owner == $user) return true; // owner already set to $user
1409
1410 /* update owner */
1411 if($existing_owner){
1412 $res = update('membership_userrecords', $fields, $where_array);
1413 return ($res ? true : false);
1414 }
1415
1416 /* add new ownership record */
1417 $fields = array_merge($fields, $where_array, array('dateAdded' => time()));
1418 $res = insert('membership_userrecords', $fields);
1419 return ($res ? true : false);
1420 }
1421 #########################################################
1422 /**
1423 * @brief get date/time format string for use in different cases.
1424 *
1425 * @param [in] $destination string, one of these: 'php' (see date function), 'mysql', 'moment'
1426 * @param [in] $datetime string, one of these: 'd' = date, 't' = time, 'dt' = both
1427 * @return string
1428 */
1429 function app_datetime_format($destination = 'php', $datetime = 'd'){
1430 switch(strtolower($destination)){
1431 case 'mysql':
1432 $date = '%m/%d/%Y';
1433 $time = '%h:%i:%s %p';
1434 break;
1435 case 'moment':
1436 $date = 'MM/DD/YYYY';
1437 $time = 'hh:mm:ss A';
1438 break;
1439 default: // php
1440 $date = 'm/d/Y';
1441 $time = 'h:i:s A';
1442 }
1443
1444 $datetime = strtolower($datetime);
1445 if($datetime == 'dt' || $datetime == 'td') return "{$date} {$time}";
1446 if($datetime == 't') return $time;
1447 return $date;
1448 }
1449 #########################################################
1450 /**
1451 * @param [in] $app_datetime string, a datetime formatted in app-specific format
1452 * @return string, mysql-formatted datetime, 'yyyy-mm-dd H:i:s', or empty string on error
1453 */
1454 function mysql_datetime($app_datetime, $date_format = null, $time_format = null){
1455 $app_datetime = trim($app_datetime);
1456
1457 if($date_format === null) $date_format = app_datetime_format('php', 'd');
1458 $date_separator = $date_format[1];
1459 if($time_format === null) $time_format = app_datetime_format('php', 't');
1460 $time24 = (strpos($time_format, 'H') !== false); // true if $time_format is 24hr rather than 12
1461
1462 $date_regex = str_replace(
1463 array('Y', 'm', 'd', '/', '.'),
1464 array('([0-9]{4})', '(1[012]|0?[1-9])', '([12][0-9]|3[01]|0?[1-9])', '\/', '\.'),
1465 $date_format
1466 );
1467
1468 $time_regex = str_replace(
1469 array('H', 'h', ':i', ':s'),
1470 array(
1471 '(1[0-9]|2[0-3]|0?[0-9])',
1472 '(1[012]|0?[0-9])',
1473 '(:([1-5][0-9]|0?[0-9]))',
1474 '(:([1-5][0-9]|0?[0-9]))?'
1475 ),
1476 $time_format
1477 );
1478 if(stripos($time_regex, ' a'))
1479 $time_regex = str_replace(array(' a', ' A'), '\s*(am|pm|a|p)?', $time_regex);
1480 else
1481 $time_regex = str_replace(array('a', 'A'), '\s*(am|pm|a|p)?', $time_regex);
1482
1483 // extract date and time
1484 $time = '';
1485 $mat = array();
1486 $regex = "/^({$date_regex})(\s+{$time_regex})?$/i";
1487 $valid_dt = preg_match($regex, $app_datetime, $mat);
1488 if(!$valid_dt || count($mat) < 5) return ''; // invlaid datetime
1489 // if we have a time, get it and change 'a' or 'p' at the end to 'am'/'pm'
1490 if(count($mat) >= 8) $time = preg_replace('/(a|p)$/i', '$1m', trim($mat[5]));
1491
1492 // extract date elements from regex match, given 1st 2 items are full string and full date
1493 $date_order = str_replace($date_separator, '', $date_format);
1494 $day = $mat[stripos($date_order, 'd') + 2];
1495 $month = $mat[stripos($date_order, 'm') + 2];
1496 $year = $mat[stripos($date_order, 'y') + 2];
1497
1498 // convert time to 24hr format if necessary
1499 if($time && !$time24) $time = date('H:i:s', strtotime("2000-01-01 {$time}"));
1500
1501 $mysql_datetime = trim("{$year}-{$month}-{$day} {$time}");
1502
1503 // strtotime handles dates between 1902 and 2037 only
1504 // so we need another test date for dates outside this range ...
1505 $test = $mysql_datetime;
1506 if($year < 1902 || $year > 2037) $test = str_replace($year, '2000', $mysql_datetime);
1507
1508 return (strtotime($test) ? $mysql_datetime : '');
1509 }
1510 #########################################################
1511 /**
1512 * @param [in] $mysql_datetime string, Mysql-formatted datetime
1513 * @param [in] $datetime string, one of these: 'd' = date, 't' = time, 'dt' = both
1514 * @return string, app-formatted datetime, or empty string on error
1515 *
1516 * @details works for formatting date, time and datetime, based on 2nd param
1517 */
1518 function app_datetime($mysql_datetime, $datetime = 'd'){
1519 $pyear = $myear = substr($mysql_datetime, 0, 4);
1520
1521 // strtotime handles dates between 1902 and 2037 only
1522 // so we need a temp date for dates outside this range ...
1523 if($myear < 1902 || $myear > 2037) $pyear = 2000;
1524 $mysql_datetime = str_replace($myear, $pyear, $mysql_datetime);
1525
1526 $ts = strtotime($mysql_datetime);
1527 if(!$ts) return '';
1528
1529 $pdate = date(app_datetime_format('php', $datetime), $ts);
1530 return str_replace($pyear, $myear, $pdate);
1531 }
1532 #########################################################
1533 /**
1534 * @brief converts string from app-configured encoding to utf8
1535 *
1536 * @param [in] $str string to convert to utf8
1537 * @return utf8-encoded string
1538 *
1539 * @details if the constant 'datalist_db_encoding' is not defined, original string is returned
1540 */
1541 function to_utf8($str) {
1542 if(!defined('datalist_db_encoding')) return $str;
1543 if(datalist_db_encoding == 'UTF-8') return $str;
1544 return iconv(datalist_db_encoding, 'UTF-8', $str);
1545 }
1546 #########################################################
1547 /**
1548 * @brief converts string from utf8 to app-configured encoding
1549 *
1550 * @param [in] $str string to convert from utf8
1551 * @return utf8-decoded string
1552 *
1553 * @details if the constant 'datalist_db_encoding' is not defined, original string is returned
1554 */
1555 function from_utf8($str) {
1556 if(!defined('datalist_db_encoding')) return $str;
1557 if(datalist_db_encoding == 'UTF-8') return $str;
1558 return iconv('UTF-8', datalist_db_encoding, $str);
1559 }